From de06878e5a295bfbbddca0048c3453d16168a676 Mon Sep 17 00:00:00 2001 From: Sergey Shepelev Date: Tue, 4 Apr 2017 17:31:22 +0300 Subject: [PATCH] ssl: RecursionError on Python3.6+; Thanks to justdoit0823@github and Gevent developers https://github.com/eventlet/eventlet/issues/371 --- eventlet/green/ssl.py | 20 ++++++++++++++++++++ tests/isolated/green_ssl_py36_properties.py | 16 ++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 tests/isolated/green_ssl_py36_properties.py diff --git a/eventlet/green/ssl.py b/eventlet/green/ssl.py index d7fbef7..a5a2062 100644 --- a/eventlet/green/ssl.py +++ b/eventlet/green/ssl.py @@ -401,6 +401,26 @@ if hasattr(__ssl, 'SSLContext'): def wrap_socket(self, sock, *a, **kw): return GreenSSLSocket(sock, *a, _context=self, **kw) + # https://github.com/eventlet/eventlet/issues/371 + # Thanks to Gevent developers for sharing patch to this problem. + if hasattr(_original_sslcontext.options, 'setter'): + # In 3.6, these became properties. They want to access the + # property __set__ method in the superclass, and they do so by using + # super(SSLContext, SSLContext). But we rebind SSLContext when we monkey + # patch, which causes infinite recursion. + # https://github.com/python/cpython/commit/328067c468f82e4ec1b5c510a4e84509e010f296 + @_original_sslcontext.options.setter + def options(self, value): + super(_original_sslcontext, _original_sslcontext).options.__set__(self, value) + + @_original_sslcontext.verify_flags.setter + def verify_flags(self, value): + super(_original_sslcontext, _original_sslcontext).verify_flags.__set__(self, value) + + @_original_sslcontext.verify_mode.setter + def verify_mode(self, value): + super(_original_sslcontext, _original_sslcontext).verify_mode.__set__(self, value) + SSLContext = GreenSSLContext if hasattr(__ssl, 'create_default_context'): diff --git a/tests/isolated/green_ssl_py36_properties.py b/tests/isolated/green_ssl_py36_properties.py new file mode 100644 index 0000000..aa6b5b5 --- /dev/null +++ b/tests/isolated/green_ssl_py36_properties.py @@ -0,0 +1,16 @@ +__test__ = False + + +if __name__ == '__main__': + import eventlet + eventlet.monkey_patch() + + try: + eventlet.wrap_ssl( + eventlet.listen(('localhost', 0)), + certfile='does-not-exist', + keyfile='does-not-exist', + server_side=True) + except IOError as ex: + assert ex.errno == 2 + print('pass')