PageRenderTime 32ms CodeModel.GetById 12ms app.highlight 14ms RepoModel.GetById 1ms app.codeStats 0ms

/gdata/tlslite/integration/TLSAsyncDispatcherMixIn.py

http://radioappz.googlecode.com/
Python | 139 lines | 134 code | 4 blank | 1 comment | 0 complexity | 980c2f9bf087074936426017893fd14e MD5 | raw file
  1"""TLS Lite + asyncore."""
  2
  3
  4import asyncore
  5from gdata.tlslite.TLSConnection import TLSConnection
  6from AsyncStateMachine import AsyncStateMachine
  7
  8
  9class 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)