-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathnettyclient.py
86 lines (71 loc) · 2.78 KB
/
nettyclient.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# Rough translation of http://docs.python.org/2/library/ssl.html#client-side-operation
from io.netty.bootstrap import Bootstrap, ChannelFactory
from io.netty.buffer import PooledByteBufAllocator, Unpooled
from io.netty.channel import ChannelInboundHandlerAdapter, ChannelInitializer, ChannelOption
from io.netty.channel.nio import NioEventLoopGroup
from io.netty.channel.socket.nio import NioSocketChannel
from io.netty.handler.ssl import SslHandler
from javax.net.ssl import SSLContext
from java.util.concurrent import TimeUnit
import jarray
from threading import Condition
class SSLInitializer(ChannelInitializer):
def initChannel(self, ch):
pipeline = ch.pipeline()
engine = SSLContext.getDefault().createSSLEngine()
engine.setUseClientMode(True);
pipeline.addLast("ssl", SslHandler(engine))
def make_request(group, host, port, req):
bootstrap = Bootstrap().\
group(group).\
channel(NioSocketChannel).\
handler(SSLInitializer()).\
option(ChannelOption.TCP_NODELAY, True).\
option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
channel = bootstrap.connect(host, port).sync().channel()
data = [None]
cv = Condition()
class ReadAdapter(ChannelInboundHandlerAdapter):
def channelRead(self, ctx, msg):
try:
length = msg.writerIndex()
print "length=", length
data[0] = buf = jarray.zeros(length, "b")
msg.getBytes(0, buf)
cv.acquire()
cv.notify()
cv.release()
finally:
msg.release()
def channelReadComplete(self, ctx):
print "Partial read"
# partial reads; this seems to be seen in SSL handshaking/wrap/unwrap
pass
channel.pipeline().addLast(ReadAdapter())
channel.writeAndFlush(Unpooled.wrappedBuffer(req)).sync()
channel.read()
# block until we get one full read; note that any real usage would
# require parsing the HTTP header (Content-Length) for the number
# of bytes to be read
cv.acquire()
while not data[0]:
cv.wait()
cv.release()
channel.close().sync()
return data[0].tostring()
def main():
group = NioEventLoopGroup()
try:
host = "www.verisign.com"
port = 443
req = """GET / HTTP/1.0\r
Host: {}\r\n\r\n""".format(host)
print make_request(group, host, port, req)
finally:
print "Shutting down group threadpool"
group.shutdown()
# Above is deprecated, but still probably works better in the context of Python;
# we expect complete cleanup, or for errors to be reported at shutdown
# group.shutdownGracefully(10, 20, TimeUnit.MILLISECONDS)
if __name__ == "__main__":
main()