Commit 853b8b2c authored by Jason Madden's avatar Jason Madden

Ensure that the ssl modules for Python 3 and 2.7.9+ get the gevent socket, not the stdlib socket.

If the environment had not been monkeypatched when gevent's ssl module
was imported, they could get the stdlib socket, meaning that reads and
writes could block greenlet switching for an arbitrary amount of time.
This was especially visible on SSL servers.

Fixes #597.
parent fd0828ab
......@@ -22,6 +22,9 @@ Unreleased
- Additional query functions for the :mod:`gevent.monkey` module
allow knowing what was patched. Discussed in :issue:`135` and
implemented in :pr:`325` by Nathan Hoad.
- In non-monkey-patched environments under Python 2.7.9 or above or
Python 3, using a gevent SSL socket could cause the greenlet to
block. See :issue:`597` by David Ford.
1.1a1 (Jun 29, 2015)
====================
......
......@@ -29,6 +29,9 @@ for name in dir(__ssl__):
continue
if name.startswith('__'):
continue
if name == 'socket':
# SSLSocket *must* subclass gevent.socket.socket; see issue 597
continue
value = getattr(__ssl__, name)
globals()[name] = value
__imports__.append(name)
......
......@@ -36,6 +36,9 @@ for name in dir(__ssl__):
continue
if name.startswith('__'):
continue
if name == 'socket':
# SSLSocket *must* subclass gevent.socket.socket; see issue 597
continue
value = getattr(__ssl__, name)
globals()[name] = value
__imports__.append(name)
......
......@@ -44,7 +44,10 @@ class Test_wsgiserver(util.TestServer):
self.assertEqual(status, '404 Not Found')
self.assertEqual(data, self.not_found_message)
def test_a_blocking_client(self):
def _do_test_a_blocking_client(self):
# We spawn this in a separate server because if it's broken
# the whole server hangs
print("Checking blocking")
with self.running_server():
# First, make sure we can talk to it.
self._test_hello()
......@@ -57,7 +60,8 @@ class Test_wsgiserver(util.TestServer):
sock_file = ssl_sock.makefile(mode='rwb')
else:
sock_file = sock.makefile(mode='rwb')
sock_file.write(b'GET /xxx HTTP/1.0\r\n\r\n')
# write an incomplete request
sock_file.write(b'GET /xxx HTTP/1.0\r\n')
sock_file.flush()
# Leave it open and not doing anything
# while the other request runs to completion.
......@@ -65,6 +69,9 @@ class Test_wsgiserver(util.TestServer):
# doesn't hang the whole server
self._test_hello()
# now finish the original request
sock_file.write(b'\r\n')
sock_file.flush()
line = sock_file.readline()
self.assertEqual(line, b'HTTP/1.1 404 Not Found\r\n')
......@@ -73,6 +80,8 @@ class Test_wsgiserver(util.TestServer):
if ssl_sock is not None:
ssl_sock.close()
def test_a_blocking_client(self):
self._do_test_a_blocking_client()
class Test_wsgiserver_ssl(Test_wsgiserver):
server = 'wsgiserver_ssl.py'
......@@ -97,6 +106,10 @@ class Test_webproxy(Test_wsgiserver):
self.assertEqual(status, '200 OK')
assert b'google' in data.lower(), repr(data)
def _do_test_a_blocking_client(self):
# Not applicable
return
# class Test_webpy(Test_wsgiserver):
# server = 'webpy.py'
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment