/gdata/tlslite/integration/TLSAsyncDispatcherMixIn.py

http://radioappz.googlecode.com/ · Python · 139 lines · 115 code · 19 blank · 5 comment · 11 complexity · 980c2f9bf087074936426017893fd14e MD5 · raw file

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