ssl: Fix "TypeError: read() argument 2 must be read-write bytes-like object, not None"

The issue would manifest after performing the following steps on
Python 3.5:

* Create a plain socket without connecting to anything
* Wrap the plain socket in an SSL socket
* Call recv(n) on the SSL socket

This is the only place in the code where we actually assign
self._sslobj, I just modified the code to wrap the sslwrap result in
SSLObject like the standard library SSLSocket.connect does[1] since
Python 3.5[2].

[1] 9ec0aa138b/Lib/ssl.py (L1008)
[2] http://bugs.python.org/issue21965
This commit is contained in:
Jakub Stasiak 2016-09-26 14:43:03 +01:00
parent 6d0103298a
commit 1d4ce40c1b
2 changed files with 43 additions and 1 deletions

View File

@ -327,7 +327,14 @@ class GreenSSLSocket(_original_sslsocket):
self.cert_reqs, self.ssl_version,
self.ca_certs, *([self.ciphers] if has_ciphers else []))
self._sslobj = sslobj
try:
# This is added in Python 3.5, http://bugs.python.org/issue21965
SSLObject
except NameError:
self._sslobj = sslobj
else:
self._sslobj = SSLObject(sslobj, owner=self)
if self.do_handshake_on_connect:
self.do_handshake()

View File

@ -86,6 +86,41 @@ class SSLTest(tests.LimitedTestCase):
ssl_client.close()
server_coro.wait()
def test_recv_after_ssl_connect(self):
def serve(listener):
sock, addr = listener.accept()
sock.sendall(b'hjk')
sock = listen_ssl_socket()
server_coro = eventlet.spawn(serve, sock)
raw_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
ssl_client = ssl.wrap_socket(raw_client)
# Important: We need to call connect() on an SSL socket, not a plain one.
# The bug was affecting that particular combination (create plain socket,
# wrap, call connect() on the SSL socket and try to recv) on Python 3.5.
ssl_client.connect(sock.getsockname())
# The call to recv used to fail with:
# Traceback (most recent call last):
# File "tests/ssl_test.py", line 99, in test_recv_after_ssl_connect
# self.assertEqual(ssl_client.recv(3), b'hjk')
# File "eventlet/green/ssl.py", line 194, in recv
# return self._base_recv(buflen, flags, into=False)
# File "eventlet/green/ssl.py", line 227, in _base_recv
# read = self.read(nbytes)
# File "eventlet/green/ssl.py", line 139, in read
# super(GreenSSLSocket, self).read, *args, **kwargs)
# File "eventlet/green/ssl.py", line 113, in _call_trampolining
# return func(*a, **kw)
# File "PYTHONLIB/python3.5/ssl.py", line 791, in read
# return self._sslobj.read(len, buffer)
# TypeError: read() argument 2 must be read-write bytes-like object, not None
self.assertEqual(ssl_client.recv(3), b'hjk')
greenio.shutdown_safe(ssl_client)
ssl_client.close()
server_coro.wait()
def test_ssl_unwrap(self):
def serve():
sock, addr = listener.accept()