homepage

This issue tracker has been migrated to GitHub , and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author mehaase
Recipients mehaase, yselivanov
Date 2017年06月23日.14:08:44
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1498226925.91.0.0585632472873.issue30740@psf.upfronthosting.co.za>
In-reply-to
Content
If a task is cancelled while it waiting for SSL negotiation, then an SSLError is raised, but there is no way (as far as I can tell) for the caller to catch it. (The example below is pretty contrived, but in an application I'm working on, the user can cancel downloads at any time.) Here's an example:
 import asyncio, random, ssl
 async def download(host):
 ssl_context = ssl.create_default_context()
 reader, writer = await asyncio.open_connection(host, 443, ssl=ssl_context)
 request = f'HEAD / HTTP/1.1\r\nHost: {host}\r\n\r\n'
 writer.write(request.encode('ascii'))
 lines = list()
 while True:
 newdata = await reader.readline()
 if newdata == b'\r\n':
 break
 else:
 lines.append(newdata.decode('utf8').rstrip('\r\n'))
 return lines[0]
 async def main():
 while True:
 task = asyncio.Task(download('www.python.org'))
 await asyncio.sleep(random.uniform(0.0, 0.5))
 task.cancel()
 try:
 response = await task
 print(response)
 except asyncio.CancelledError:
 print('request cancelled!')
 except ssl.SSLError:
 print('caught SSL error')
 await asyncio.sleep(1)
 loop = asyncio.get_event_loop()
 loop.run_until_complete(main())
 loop.close()
Running this script yields the following output:
 HTTP/1.1 200 OK
 request cancelled!
 HTTP/1.1 200 OK
 HTTP/1.1 200 OK
 <asyncio.sslproto.SSLProtocol object at 0x7fe7c00e5a20>: SSL handshake failed
 Traceback (most recent call last):
 File "/usr/lib/python3.6/asyncio/base_events.py", line 803, in _create_connection_transport
 yield from waiter
 File "/usr/lib/python3.6/asyncio/tasks.py", line 304, in _wakeup
 future.result()
 concurrent.futures._base.CancelledError
 During handling of the above exception, another exception occurred:
 Traceback (most recent call last):
 File "/usr/lib/python3.6/asyncio/sslproto.py", line 577, in _on_handshake_complete
 raise handshake_exc
 File "/usr/lib/python3.6/asyncio/sslproto.py", line 638, in _process_write_backlog
 ssldata = self._sslpipe.shutdown(self._finalize)
 File "/usr/lib/python3.6/asyncio/sslproto.py", line 155, in shutdown
 ssldata, appdata = self.feed_ssldata(b'')
 File "/usr/lib/python3.6/asyncio/sslproto.py", line 219, in feed_ssldata
 self._sslobj.unwrap()
 File "/usr/lib/python3.6/ssl.py", line 692, in unwrap
 return self._sslobj.shutdown()
 ssl.SSLError: [SSL] shutdown while in init (_ssl.c:2299)
I posted this on async-sig, and Nathaniel replied:
> SSLObject.unwrap has the contract that if it finishes successfully, then the SSL connection has been cleanly shut down and both sides remain in sync, and can continue to use the socket in unencrypted mode. When asyncio calls unwrap before the handshake has completed, then this contract is impossible to fulfill, and raising an error is the right thing to do. So imo the ssl module is correct here, and this is a (minor) bug in asyncio.
The unwrap() call that throws is already wrapped in `try ... except SSLError` but the exception handler checks for specific SSL error codes and re-throws this particular SSL error. 
 except (ssl.SSLError, ssl.CertificateError) as exc:
 if getattr(exc, 'errno', None) not in (
 ssl.SSL_ERROR_WANT_READ, ssl.SSL_ERROR_WANT_WRITE,
 ssl.SSL_ERROR_SYSCALL):
 if self._state == _DO_HANDSHAKE and self._handshake_cb:
 self._handshake_cb(exc)
 raise
 self._need_ssldata = (exc.errno == ssl.SSL_ERROR_WANT_READ)
I think this could be fixed checking for SSL_R_SHUTDOWN_WHILE_IN_INIT in this exception handler, but that constant doesn't exist in _ssl.c.
As an alternative, maybe a new state _ABORT_HANDSHAKE could be introduced (the existing states are _DO_HANDSHAKE, _WRAPPED, _SHUTDOWN, and _UNWRAP).
I'm happy to try my hand at either one of these approaches if somebody can point me in the right direction.
History
Date User Action Args
2017年06月23日 14:08:45mehaasesetrecipients: + mehaase, yselivanov
2017年06月23日 14:08:45mehaasesetmessageid: <1498226925.91.0.0585632472873.issue30740@psf.upfronthosting.co.za>
2017年06月23日 14:08:45mehaaselinkissue30740 messages
2017年06月23日 14:08:44mehaasecreate

AltStyle によって変換されたページ (->オリジナル) /