diff --git a/eventlet/green/socket.py b/eventlet/green/socket.py index 648a99b..0607346 100644 --- a/eventlet/green/socket.py +++ b/eventlet/green/socket.py @@ -4,7 +4,9 @@ for var in __socket.__all__: _fileobject = __socket._fileobject from eventlet.api import get_hub -from eventlet.greenio import GreenSocket as socket, GreenSSL as _GreenSSL +from eventlet.greenio import GreenSocket as socket +from eventlet.greenio import GreenSSL as _GreenSSL +from eventlet.greenio import GreenSSLObject as _GreenSSLObject from eventlet.greenio import socketpair, fromfd def fromfd(*args): @@ -79,4 +81,4 @@ def ssl(sock, certificate=None, private_key=None): ## TODO only do this on client sockets? how? connection = SSL.Connection(context, sock) connection.set_connect_state() - return _GreenSSL(connection) + return _GreenSSLObject(_GreenSSL(connection)) diff --git a/eventlet/greenio.py b/eventlet/greenio.py index 139bc04..2a03609 100644 --- a/eventlet/greenio.py +++ b/eventlet/greenio.py @@ -606,6 +606,46 @@ class GreenSSL(GreenSocket): def pending(self, *args, **kw): fn = self.pending = self.fd.pending return fn(*args, **kw) + + +class GreenSSLObject(object): + """ Wrapper object around the SSLObjects returned by socket.ssl, which have a + slightly different interface from SSL.Connection objects. """ + def __init__(self, green_ssl_obj): + """ Should only be called by a 'green' socket.ssl """ + assert(isinstance(green_ssl_obj, GreenSSL)) + self.connection = green_ssl_obj + + def read(self, n=None): + """If n is provided, read n bytes from the SSL connection, otherwise read + until EOF. The return value is a string of the bytes read.""" + if n is None: + # don't support this until someone needs it + raise NotImplementedError("GreenSSLObject does not support "\ + " unlimited reads until we hear of someone needing to use them.") + else: + return self.connection.read(n) + + def write(self, s): + """Writes the string s to the on the object's SSL connection. + The return value is the number of bytes written. """ + return self.connection.write(s) + + def server(self): + """ Returns a string describing the server's certificate. Useful for debugging + purposes; do not parse the content of this string because its format can't be + parsed unambiguously. """ + # NOTE: probably not the same as the real SSLObject, but, if someone actually + # uses this then we can fix it. + return str(self.connection.get_peer_certificate()) + + def issuer(self): + """Returns a string describing the issuer of the server's certificate. Useful + for debugging purposes; do not parse the content of this string because its + format can't be parsed unambiguously.""" + # NOTE: probably not the same as the real SSLObject, but, if someone actually + # uses this then we can fix it. + return str(self.connection.get_peer_certificate().get_issuer()) def socketpair(*args): diff --git a/eventlet/util.py b/eventlet/util.py index 694ffe1..5597925 100644 --- a/eventlet/util.py +++ b/eventlet/util.py @@ -102,7 +102,11 @@ def wrap_socket_with_coroutine_socket(use_thread_pool=True): return greenio.GreenSocket(__original_socket__(*args, **kw)) socket.socket = new_socket - socket.ssl = wrap_ssl + # for 100% compatibility, return a GreenSSLObject + def new_ssl(sock, certificate=None, private_key=None): + wrapped = wrap_ssl(sock, certificate, private_key) + return greenio.GreenSSLObject(wrapped) + socket.ssl = new_ssl if use_thread_pool: from eventlet import tpool