summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Lib/asyncio/sslproto.py13
-rw-r--r--Lib/test/test_asyncio/test_sslproto.py15
-rw-r--r--Misc/NEWS.d/next/Library/2023-12-20-21-18-51.gh-issue-113214.JcV9Mn.rst1
3 files changed, 21 insertions, 8 deletions
diff --git a/Lib/asyncio/sslproto.py b/Lib/asyncio/sslproto.py
index 3eb65a8..cbb6527 100644
--- a/Lib/asyncio/sslproto.py
+++ b/Lib/asyncio/sslproto.py
@@ -243,13 +243,12 @@ class _SSLProtocolTransport(transports._FlowControlMixin,
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()
+ self._force_close(None)
def _force_close(self, exc):
self._closed = True
- self._ssl_protocol._abort(exc)
+ if self._ssl_protocol is not None:
+ self._ssl_protocol._abort(exc)
def _test__append_write_backlog(self, data):
# for test only
@@ -614,7 +613,7 @@ class SSLProtocol(protocols.BufferedProtocol):
if self._app_transport is not None:
self._app_transport._closed = True
if self._state == SSLProtocolState.DO_HANDSHAKE:
- self._abort()
+ self._abort(None)
else:
self._set_state(SSLProtocolState.FLUSHING)
self._shutdown_timeout_handle = self._loop.call_later(
@@ -661,10 +660,10 @@ class SSLProtocol(protocols.BufferedProtocol):
else:
self._loop.call_soon(self._transport.close)
- def _abort(self):
+ def _abort(self, exc):
self._set_state(SSLProtocolState.UNWRAPPED)
if self._transport is not None:
- self._transport.abort()
+ self._transport._force_close(exc)
# Outgoing flow
diff --git a/Lib/test/test_asyncio/test_sslproto.py b/Lib/test/test_asyncio/test_sslproto.py
index 37d0153..f5f0afe 100644
--- a/Lib/test/test_asyncio/test_sslproto.py
+++ b/Lib/test/test_asyncio/test_sslproto.py
@@ -47,6 +47,7 @@ class SslProtoHandshakeTests(test_utils.TestCase):
sslobj = mock.Mock()
# emulate reading decompressed data
sslobj.read.side_effect = ssl.SSLWantReadError
+ sslobj.write.side_effect = ssl.SSLWantReadError
if do_handshake is not None:
sslobj.do_handshake = do_handshake
ssl_proto._sslobj = sslobj
@@ -120,7 +121,19 @@ class SslProtoHandshakeTests(test_utils.TestCase):
test_utils.run_briefly(self.loop)
ssl_proto._app_transport.close()
- self.assertTrue(transport.abort.called)
+ self.assertTrue(transport._force_close.called)
+
+ def test_close_during_ssl_over_ssl(self):
+ # gh-113214: passing exceptions from the inner wrapped SSL protocol to the
+ # shim transport provided by the outer SSL protocol should not raise
+ # attribute errors
+ outer = self.ssl_protocol(proto=self.ssl_protocol())
+ self.connection_made(outer)
+ # Closing the outer app transport should not raise an exception
+ messages = []
+ self.loop.set_exception_handler(lambda loop, ctx: messages.append(ctx))
+ outer._app_transport.close()
+ self.assertEqual(messages, [])
def test_get_extra_info_on_closed_connection(self):
waiter = self.loop.create_future()
diff --git a/Misc/NEWS.d/next/Library/2023-12-20-21-18-51.gh-issue-113214.JcV9Mn.rst b/Misc/NEWS.d/next/Library/2023-12-20-21-18-51.gh-issue-113214.JcV9Mn.rst
new file mode 100644
index 0000000..6db74cd
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-12-20-21-18-51.gh-issue-113214.JcV9Mn.rst
@@ -0,0 +1 @@
+Fix an ``AttributeError`` during asyncio SSL protocol aborts in SSL-over-SSL scenarios.