-
-
Notifications
You must be signed in to change notification settings - Fork 32.4k
Description
Bug report
Bug description:
There are several pathways to this bug, all which call asyncio.sslproto._SSLProtocolTransport._force_close()
with an exception instance:
- During shutdown, if the flushing state takes too long (
asyncio.sslproto.SSLProtocolTransport._check_shutdown_timeout()
is called) - Anything that triggers a call to
asyncio.sslproto.SSLProtocol._fatal_error()
, e.g. SSL handshake timeout or exception, SSL shutdown timeout or exception, an exception during reading, exception raised in the app transport EOF handler, etc.
I'm seeing this when using a HTTPS proxy with a aiohttp client session (which wraps TLS in TLS), but I don't think it is specific to that context. I'm seeing these tracebacks:
Fatal error on SSL protocol
protocol: <asyncio.sslproto.SSLProtocol object at 0x7fe36f3a1350>
transport: <_SelectorSocketTransport closing fd=6 read=idle write=<idle, bufsize=0>>
Traceback (most recent call last):
File ".../lib/python3.11/asyncio/sslproto.py", line 644, in _do_shutdown
self._sslobj.unwrap()
File ".../lib/python3.11/ssl.py", line 983, in unwrap
return self._sslobj.shutdown()
^^^^^^^^^^^^^^^^^^^^^^^
ssl.SSLError: [SSL: APPLICATION_DATA_AFTER_CLOSE_NOTIFY] application data after close notify (_ssl.c:2702)
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File ".../lib/python3.11/asyncio/sslproto.py", line 731, in _do_read
self._do_read__buffered()
File ".../lib/python3.11/asyncio/sslproto.py", line 765, in _do_read__buffered
self._app_protocol_buffer_updated(offset)
File ".../lib/python3.11/asyncio/sslproto.py", line 445, in buffer_updated
self._do_shutdown()
File ".../lib/python3.11/asyncio/sslproto.py", line 648, in _do_shutdown
self._on_shutdown_complete(exc)
File ".../lib/python3.11/asyncio/sslproto.py", line 660, in _on_shutdown_complete
self._fatal_error(shutdown_exc)
File ".../lib/python3.11/asyncio/sslproto.py", line 911, in _fatal_error
self._transport._force_close(exc)
File ".../lib/python3.11/asyncio/sslproto.py", line 252, in _force_close
self._ssl_protocol._abort(exc)
TypeError: SSLProtocol._abort() takes 1 positional argument but 2 were given
To me, the implementation of _SSLProtocolTransport._force_close()
looks like an unfinished copy of the _SSLProtocolTransport.abort()
method:
cpython/Lib/asyncio/sslproto.py
Lines 239 to 252 in 1583c40
def abort(self): | |
"""Close the transport immediately. | |
Buffered data will be lost. No more data will be received. | |
The protocol's connection_lost() method will (eventually) be | |
called with None as its argument. | |
""" | |
self._closed = True | |
if self._ssl_protocol is not None: | |
self._ssl_protocol._abort() | |
def _force_close(self, exc): | |
self._closed = True | |
self._ssl_protocol._abort(exc) |
At any rate, the self._ssl_protocol
attribute is an instance of SSLProtocol
in the same module, and the _abort()
method on that class doesn't accept an exception instance:
cpython/Lib/asyncio/sslproto.py
Lines 664 to 667 in 1583c40
def _abort(self): | |
self._set_state(SSLProtocolState.UNWRAPPED) | |
if self._transport is not None: | |
self._transport.abort() |
I find the test suite surrounding the SSL protocol to be dense enough that I can't easily spot how to provide an update there to reproduce this issue more easily, but the fix looks simple enough: don't pass an argument to _abort()
.
CPython versions tested on:
3.11, 3.12, CPython main branch
Operating systems tested on:
Linux
Linked PRs
Metadata
Metadata
Assignees
Labels
Projects
Status