diff options
author | Junyi <xmaswillyou@gmail.com> | 2019-01-30 00:10:31 -0800 |
---|---|---|
committer | Jakub Stasiak <jakub@stasiak.at> | 2019-01-30 09:10:31 +0100 |
commit | a915bb642dd6cd4e92c959addff30509977a637c (patch) | |
tree | 5642f3df83f8e76a5e8e7724fe1e6af13ec5468f | |
parent | 05d613d8ed123b87f64f8d1987968c5bf825b07a (diff) | |
download | eventlet-a915bb642dd6cd4e92c959addff30509977a637c.tar.gz |
Fix compatibility with Python 3.7 ssl.SSLSocket (#531)
-rw-r--r-- | eventlet/green/ssl.py | 86 | ||||
-rw-r--r-- | eventlet/greenio/base.py | 4 |
2 files changed, 52 insertions, 38 deletions
diff --git a/eventlet/green/ssl.py b/eventlet/green/ssl.py index 53dff70..9504aef 100644 --- a/eventlet/green/ssl.py +++ b/eventlet/green/ssl.py @@ -3,10 +3,7 @@ __ssl = __import__('ssl') from eventlet.patcher import slurp_properties slurp_properties(__ssl, globals(), srckeys=dir(__ssl)) -import errno -import functools import sys - from eventlet import greenio, hubs from eventlet.greenio import ( set_nonblocking, GreenSocket, CONNECT_ERR, CONNECT_SUCCESS, @@ -14,6 +11,8 @@ from eventlet.greenio import ( from eventlet.hubs import trampoline, IOClosed from eventlet.support import get_errno, PY33 import six +from contextlib import contextmanager + orig_socket = __import__('socket') socket = orig_socket.socket timeout_exc = SSLError @@ -24,6 +23,21 @@ __patched__ = [ _original_sslsocket = __ssl.SSLSocket _original_wrap_socket = __ssl.wrap_socket +_original_sslcontext = getattr(__ssl, 'SSLContext', None) +_is_under_py_3_7 = sys.version_info < (3, 7) + + +@contextmanager +def _original_ssl_context(*args, **kwargs): + tmp_sslcontext = _original_wrap_socket.__globals__.get('SSLContext', None) + tmp_sslsocket = _original_sslsocket._create.__globals__.get('SSLSocket', None) + _original_sslsocket._create.__globals__['SSLSocket'] = _original_sslsocket + _original_wrap_socket.__globals__['SSLContext'] = _original_sslcontext + try: + yield + finally: + _original_wrap_socket.__globals__['SSLContext'] = tmp_sslcontext + _original_sslsocket._create.__globals__['SSLSocket'] = tmp_sslsocket class GreenSSLSocket(_original_sslsocket): @@ -40,16 +54,43 @@ class GreenSSLSocket(_original_sslsocket): settimeout(), and to close/reopen the connection when a timeout occurs at an unexpected juncture in the code. """ + def __new__(cls, sock=None, keyfile=None, certfile=None, + server_side=False, cert_reqs=CERT_NONE, + ssl_version=PROTOCOL_SSLv23, ca_certs=None, + do_handshake_on_connect=True, *args, **kw): + if _is_under_py_3_7: + return super(GreenSSLSocket, cls).__new__(cls) + else: + if not isinstance(sock, GreenSocket): + sock = GreenSocket(sock) + with _original_ssl_context(): + ret = _original_wrap_socket( + sock=sock.fd, + keyfile=keyfile, + certfile=certfile, + server_side=server_side, + cert_reqs=cert_reqs, + ssl_version=ssl_version, + ca_certs=ca_certs, + do_handshake_on_connect=False, + *args, **kw + ) + ret.keyfile = keyfile + ret.certfile = certfile + ret.cert_reqs = cert_reqs + ret.ssl_version = ssl_version + ret.ca_certs = ca_certs + ret.__class__ = GreenSSLSocket + return ret + # we are inheriting from SSLSocket because its constructor calls # do_handshake whose behavior we wish to override - def __init__(self, sock, keyfile=None, certfile=None, server_side=False, cert_reqs=CERT_NONE, ssl_version=PROTOCOL_SSLv23, ca_certs=None, do_handshake_on_connect=True, *args, **kw): if not isinstance(sock, GreenSocket): sock = GreenSocket(sock) - self.act_non_blocking = sock.act_non_blocking if six.PY2: @@ -57,42 +98,12 @@ class GreenSSLSocket(_original_sslsocket): # this assignment self._timeout = sock.gettimeout() - if sys.version_info >= (3, 7): - # Monkey-patch the sslsocket so our modified self gets - # injected into its _create method. - def fake_new(self, cls, *args, **kwargs): - return self - - orig_new = _original_sslsocket.__new__ - try: - _original_sslsocket.__new__ = fake_new.__get__(self, GreenSSLSocket) - - self = _original_wrap_socket( - sock=sock.fd, - keyfile=keyfile, - certfile=certfile, - server_side=server_side, - cert_reqs=cert_reqs, - ssl_version=ssl_version, - ca_certs=ca_certs, - do_handshake_on_connect=False, - *args, **kw - ) - self.keyfile = keyfile - self.certfile = certfile - self.cert_reqs = cert_reqs - self.ssl_version = ssl_version - self.ca_certs = ca_certs - finally: - # Unpatch - _original_sslsocket.__new__ = orig_new - else: + if _is_under_py_3_7: # nonblocking socket handshaking on connect got disabled so let's pretend it's disabled # even when it's on super(GreenSSLSocket, self).__init__( sock.fd, keyfile, certfile, server_side, cert_reqs, ssl_version, ca_certs, do_handshake_on_connect and six.PY2, *args, **kw) - # the superclass initializer trashes the methods so we remove # the local-object versions of them and let the actual class # methods shine through @@ -354,7 +365,7 @@ class GreenSSLSocket(_original_sslsocket): except NameError: self._sslobj = sslobj else: - if sys.version_info < (3, 7): + if _is_under_py_3_7: self._sslobj = SSLObject(sslobj, owner=self) else: self._sslobj = sslobj @@ -396,6 +407,7 @@ class GreenSSLSocket(_original_sslsocket): def dup(self): raise NotImplementedError("Can't dup an ssl object") + SSLSocket = GreenSSLSocket diff --git a/eventlet/greenio/base.py b/eventlet/greenio/base.py index 4a9a640..ce53b54 100644 --- a/eventlet/greenio/base.py +++ b/eventlet/greenio/base.py @@ -145,7 +145,9 @@ class GreenSocket(object): except AttributeError: self._timeout = socket.getdefaulttimeout() - if should_set_nonblocking: + # Filter fd.fileno() != -1 so that won't call set non-blocking on + # closed socket + if should_set_nonblocking and fd.fileno() != -1: set_nonblocking(fd) self.fd = fd # when client calls setblocking(0) or settimeout(0) the socket must |