OLD | NEW |
| (Empty) |
1 """TLS Lite + asyncore.""" | |
2 | |
3 | |
4 import asyncore | |
5 from tlslite.TLSConnection import TLSConnection | |
6 from AsyncStateMachine import AsyncStateMachine | |
7 | |
8 | |
9 class TLSAsyncDispatcherMixIn(AsyncStateMachine): | |
10 """This class can be "mixed in" with an | |
11 L{asyncore.dispatcher} to add TLS support. | |
12 | |
13 This class essentially sits between the dispatcher and the select | |
14 loop, intercepting events and only calling the dispatcher when | |
15 applicable. | |
16 | |
17 In the case of handle_read(), a read operation will be activated, | |
18 and when it completes, the bytes will be placed in a buffer where | |
19 the dispatcher can retrieve them by calling recv(), and the | |
20 dispatcher's handle_read() will be called. | |
21 | |
22 In the case of handle_write(), the dispatcher's handle_write() will | |
23 be called, and when it calls send(), a write operation will be | |
24 activated. | |
25 | |
26 To use this class, you must combine it with an asyncore.dispatcher, | |
27 and pass in a handshake operation with setServerHandshakeOp(). | |
28 | |
29 Below is an example of using this class with medusa. This class is | |
30 mixed in with http_channel to create http_tls_channel. Note: | |
31 1. the mix-in is listed first in the inheritance list | |
32 | |
33 2. the input buffer size must be at least 16K, otherwise the | |
34 dispatcher might not read all the bytes from the TLS layer, | |
35 leaving some bytes in limbo. | |
36 | |
37 3. IE seems to have a problem receiving a whole HTTP response in a | |
38 single TLS record, so HTML pages containing '\\r\\n\\r\\n' won't | |
39 be displayed on IE. | |
40 | |
41 Add the following text into 'start_medusa.py', in the 'HTTP Server' | |
42 section:: | |
43 | |
44 from tlslite.api import * | |
45 s = open("./serverX509Cert.pem").read() | |
46 x509 = X509() | |
47 x509.parse(s) | |
48 certChain = X509CertChain([x509]) | |
49 | |
50 s = open("./serverX509Key.pem").read() | |
51 privateKey = parsePEMKey(s, private=True) | |
52 | |
53 class http_tls_channel(TLSAsyncDispatcherMixIn, | |
54 http_server.http_channel): | |
55 ac_in_buffer_size = 16384 | |
56 | |
57 def __init__ (self, server, conn, addr): | |
58 http_server.http_channel.__init__(self, server, conn, addr) | |
59 TLSAsyncDispatcherMixIn.__init__(self, conn) | |
60 self.tlsConnection.ignoreAbruptClose = True | |
61 self.setServerHandshakeOp(certChain=certChain, | |
62 privateKey=privateKey) | |
63 | |
64 hs.channel_class = http_tls_channel | |
65 | |
66 If the TLS layer raises an exception, the exception will be caught | |
67 in asyncore.dispatcher, which will call close() on this class. The | |
68 TLS layer always closes the TLS connection before raising an | |
69 exception, so the close operation will complete right away, causing | |
70 asyncore.dispatcher.close() to be called, which closes the socket | |
71 and removes this instance from the asyncore loop. | |
72 | |
73 """ | |
74 | |
75 | |
76 def __init__(self, sock=None): | |
77 AsyncStateMachine.__init__(self) | |
78 | |
79 if sock: | |
80 self.tlsConnection = TLSConnection(sock) | |
81 | |
82 #Calculate the sibling I'm being mixed in with. | |
83 #This is necessary since we override functions | |
84 #like readable(), handle_read(), etc., but we | |
85 #also want to call the sibling's versions. | |
86 for cl in self.__class__.__bases__: | |
87 if cl != TLSAsyncDispatcherMixIn and cl != AsyncStateMachine: | |
88 self.siblingClass = cl | |
89 break | |
90 else: | |
91 raise AssertionError() | |
92 | |
93 def readable(self): | |
94 result = self.wantsReadEvent() | |
95 if result != None: | |
96 return result | |
97 return self.siblingClass.readable(self) | |
98 | |
99 def writable(self): | |
100 result = self.wantsWriteEvent() | |
101 if result != None: | |
102 return result | |
103 return self.siblingClass.writable(self) | |
104 | |
105 def handle_read(self): | |
106 self.inReadEvent() | |
107 | |
108 def handle_write(self): | |
109 self.inWriteEvent() | |
110 | |
111 def outConnectEvent(self): | |
112 self.siblingClass.handle_connect(self) | |
113 | |
114 def outCloseEvent(self): | |
115 asyncore.dispatcher.close(self) | |
116 | |
117 def outReadEvent(self, readBuffer): | |
118 self.readBuffer = readBuffer | |
119 self.siblingClass.handle_read(self) | |
120 | |
121 def outWriteEvent(self): | |
122 self.siblingClass.handle_write(self) | |
123 | |
124 def recv(self, bufferSize=16384): | |
125 if bufferSize < 16384 or self.readBuffer == None: | |
126 raise AssertionError() | |
127 returnValue = self.readBuffer | |
128 self.readBuffer = None | |
129 return returnValue | |
130 | |
131 def send(self, writeBuffer): | |
132 self.setWriteOp(writeBuffer) | |
133 return len(writeBuffer) | |
134 | |
135 def close(self): | |
136 if hasattr(self, "tlsConnection"): | |
137 self.setCloseOp() | |
138 else: | |
139 asyncore.dispatcher.close(self) | |
OLD | NEW |