summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuido van Rossum <guido@dropbox.com>2013-11-01 21:22:30 (GMT)
committerGuido van Rossum <guido@dropbox.com>2013-11-01 21:22:30 (GMT)
commit28dff0d8238aa8f34e7858209e598f1db8bfbf70 (patch)
tree94ccbc396c7c320e0b130f077d92603fce976029
parenta8d630a6e6190a4873a16a6a8c02f561e1e1c7fe (diff)
downloadcpython-28dff0d8238aa8f34e7858209e598f1db8bfbf70.zip
cpython-28dff0d8238aa8f34e7858209e598f1db8bfbf70.tar.gz
cpython-28dff0d8238aa8f34e7858209e598f1db8bfbf70.tar.bz2
asyncio: Better-looking errors when ssl module cannot be imported. In part by Arnaud Faure.
-rw-r--r--Lib/asyncio/base_events.py2
-rw-r--r--Lib/asyncio/selector_events.py31
-rw-r--r--Lib/test/test_asyncio/test_selector_events.py20
3 files changed, 41 insertions, 12 deletions
diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py
index a73b3d3..f2d117b 100644
--- a/Lib/asyncio/base_events.py
+++ b/Lib/asyncio/base_events.py
@@ -466,6 +466,8 @@ class BaseEventLoop(events.AbstractEventLoop):
ssl=None,
reuse_address=None):
"""XXX"""
+ if isinstance(ssl, bool):
+ raise TypeError('ssl argument must be an SSLContext or None')
if host is not None or port is not None:
if sock is not None:
raise ValueError(
diff --git a/Lib/asyncio/selector_events.py b/Lib/asyncio/selector_events.py
index c5fc5eb..3bad198 100644
--- a/Lib/asyncio/selector_events.py
+++ b/Lib/asyncio/selector_events.py
@@ -90,12 +90,13 @@ class BaseSelectorEventLoop(base_events.BaseEventLoop):
except (BlockingIOError, InterruptedError):
pass
- def _start_serving(self, protocol_factory, sock, ssl=None, server=None):
+ def _start_serving(self, protocol_factory, sock,
+ sslcontext=None, server=None):
self.add_reader(sock.fileno(), self._accept_connection,
- protocol_factory, sock, ssl, server)
+ protocol_factory, sock, sslcontext, server)
- def _accept_connection(self, protocol_factory, sock, ssl=None,
- server=None):
+ def _accept_connection(self, protocol_factory, sock,
+ sslcontext=None, server=None):
try:
conn, addr = sock.accept()
conn.setblocking(False)
@@ -113,13 +114,13 @@ class BaseSelectorEventLoop(base_events.BaseEventLoop):
self.remove_reader(sock.fileno())
self.call_later(constants.ACCEPT_RETRY_DELAY,
self._start_serving,
- protocol_factory, sock, ssl, server)
+ protocol_factory, sock, sslcontext, server)
else:
raise # The event loop will catch, log and ignore it.
else:
- if ssl:
+ if sslcontext:
self._make_ssl_transport(
- conn, protocol_factory(), ssl, None,
+ conn, protocol_factory(), sslcontext, None,
server_side=True, extra={'peername': addr}, server=server)
else:
self._make_socket_transport(
@@ -558,17 +559,23 @@ class _SelectorSslTransport(_SelectorTransport):
def __init__(self, loop, rawsock, protocol, sslcontext, waiter=None,
server_side=False, server_hostname=None,
extra=None, server=None):
+ if ssl is None:
+ raise RuntimeError('stdlib ssl module not available')
+
if server_side:
- assert isinstance(
- sslcontext, ssl.SSLContext), 'Must pass an SSLContext'
+ if not sslcontext:
+ raise ValueError('Server side ssl needs a valid SSLContext')
else:
- # Client-side may pass ssl=True to use a default context.
- # The default is the same as used by urllib.
- if sslcontext is None:
+ if not sslcontext:
+ # Client side may pass ssl=True to use a default
+ # context; in that case the sslcontext passed is None.
+ # The default is the same as used by urllib with
+ # cadefault=True.
sslcontext = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
sslcontext.options |= ssl.OP_NO_SSLv2
sslcontext.set_default_verify_paths()
sslcontext.verify_mode = ssl.CERT_REQUIRED
+
wrap_kwargs = {
'server_side': server_side,
'do_handshake_on_connect': False,
diff --git a/Lib/test/test_asyncio/test_selector_events.py b/Lib/test/test_asyncio/test_selector_events.py
index 3b8238d..04a7d0c 100644
--- a/Lib/test/test_asyncio/test_selector_events.py
+++ b/Lib/test/test_asyncio/test_selector_events.py
@@ -43,6 +43,7 @@ class BaseSelectorEventLoopTests(unittest.TestCase):
self.assertIsInstance(
self.loop._make_socket_transport(m, m), _SelectorSocketTransport)
+ @unittest.skipIf(ssl is None, 'No ssl module')
def test_make_ssl_transport(self):
m = unittest.mock.Mock()
self.loop.add_reader = unittest.mock.Mock()
@@ -52,6 +53,16 @@ class BaseSelectorEventLoopTests(unittest.TestCase):
self.assertIsInstance(
self.loop._make_ssl_transport(m, m, m, m), _SelectorSslTransport)
+ @unittest.mock.patch('asyncio.selector_events.ssl', None)
+ def test_make_ssl_transport_without_ssl_error(self):
+ m = unittest.mock.Mock()
+ self.loop.add_reader = unittest.mock.Mock()
+ self.loop.add_writer = unittest.mock.Mock()
+ self.loop.remove_reader = unittest.mock.Mock()
+ self.loop.remove_writer = unittest.mock.Mock()
+ with self.assertRaises(RuntimeError):
+ self.loop._make_ssl_transport(m, m, m, m)
+
def test_close(self):
ssock = self.loop._ssock
ssock.fileno.return_value = 7
@@ -1277,6 +1288,15 @@ class SelectorSslTransportTests(unittest.TestCase):
server_hostname='localhost')
+class SelectorSslWithoutSslTransportTests(unittest.TestCase):
+
+ @unittest.mock.patch('asyncio.selector_events.ssl', None)
+ def test_ssl_transport_requires_ssl_module(self):
+ Mock = unittest.mock.Mock
+ with self.assertRaises(RuntimeError):
+ transport = _SelectorSslTransport(Mock(), Mock(), Mock(), Mock())
+
+
class SelectorDatagramTransportTests(unittest.TestCase):
def setUp(self):