[Async-sig] Cancelling SSL connection
Mark E. Haase
mehaase at gmail.com
Fri Jun 23 10:11:10 EDT 2017
Thanks Dima & Nathaniel. I opened an asyncio bug. (
http://bugs.python.org/issue30740)
Cheers,
Mark
On Wed, Jun 21, 2017 at 6:47 PM, Nathaniel Smith <njs at pobox.com> wrote:
> 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.
>
> On Jun 21, 2017 12:49 PM, "Dima Tisnek" <dimaqq at gmail.com> wrote:
>
>> Looks like a bug in the `ssl` module, not `asyncio`.
>>
>> Refer to https://github.com/openssl/openssl/issues/710
>> IMO `ssl` module should be prepared for this.
>>
>> I'd say post a bug to cpython and see what core devs have to say about it
>> :)
>> Please note exact versions of python and openssl ofc.
>>
>> my 2c: openssl has been a moving target every so often, it's quite
>> possible that this change in the API escaped the devs.
>>
>> On 21 June 2017 at 19:50, Mark E. Haase <mehaase at gmail.com> wrote:
>> > (I'm not sure if this is a newbie question or a bug report or something
>> in
>> > between. I apologize in advance if its off-topic. Let me know if I
>> should
>> > post this somewhere else.)
>> >
>> > If a task is cancelled while SSL is being negotiated, then an SSLError
>> is
>> > raised, but there's 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)
>> >
>> > Is this a bug that I should file, or is there some reason that it's
>> intended
>> > to work this way? I can work around it with asyncio.shield(), but I
>> think I
>> > would prefer for the asyncio/sslproto.py to catch the SSLError and
>> ignore
>> > it. Maybe I'm being short sighted.
>> >
>> > Thanks,
>> > Mark
>> >
>> > _______________________________________________
>> > Async-sig mailing list
>> > Async-sig at python.org
>> > https://mail.python.org/mailman/listinfo/async-sig
>> > Code of Conduct: https://www.python.org/psf/codeofconduct/
>> >
>> _______________________________________________
>> Async-sig mailing list
>> Async-sig at python.org
>> https://mail.python.org/mailman/listinfo/async-sig
>> Code of Conduct: https://www.python.org/psf/codeofconduct/
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/async-sig/attachments/20170623/4dd19704/attachment.html>
More information about the Async-sig
mailing list