summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJavad Shafique <javadshafique@hotmail.com>2024-10-24 17:41:16 (GMT)
committerGitHub <noreply@github.com>2024-10-24 17:41:16 (GMT)
commit3f24bde0b6689b8f05872a8118a97908b5a94659 (patch)
tree4769ae0e596a88ea20ffa384ed22fb95282888c6
parent41bd9d959ccdb1095b6662b903bb3cbd2a47087b (diff)
downloadcpython-3f24bde0b6689b8f05872a8118a97908b5a94659.zip
cpython-3f24bde0b6689b8f05872a8118a97908b5a94659.tar.gz
cpython-3f24bde0b6689b8f05872a8118a97908b5a94659.tar.bz2
gh-118950: Fix SSLProtocol.connection_lost not being called when OSError is thrown (#118960)
Co-authored-by: Kumar Aditya <kumaraditya@python.org>
-rw-r--r--Lib/asyncio/sslproto.py5
-rw-r--r--Lib/test/test_asyncio/test_sslproto.py48
-rw-r--r--Misc/NEWS.d/next/Core and Builtins/2024-05-12-03-10-36.gh-issue-118950.5Wc4vp.rst1
3 files changed, 53 insertions, 1 deletions
diff --git a/Lib/asyncio/sslproto.py b/Lib/asyncio/sslproto.py
index fa99d45..74c5f0d 100644
--- a/Lib/asyncio/sslproto.py
+++ b/Lib/asyncio/sslproto.py
@@ -101,7 +101,7 @@ class _SSLProtocolTransport(transports._FlowControlMixin,
return self._ssl_protocol._app_protocol
def is_closing(self):
- return self._closed
+ return self._closed or self._ssl_protocol._is_transport_closing()
def close(self):
"""Close the transport.
@@ -379,6 +379,9 @@ class SSLProtocol(protocols.BufferedProtocol):
self._app_transport_created = True
return self._app_transport
+ def _is_transport_closing(self):
+ return self._transport is not None and self._transport.is_closing()
+
def connection_made(self, transport):
"""Called when the low-level connection is made.
diff --git a/Lib/test/test_asyncio/test_sslproto.py b/Lib/test/test_asyncio/test_sslproto.py
index f5f0afe..761904c 100644
--- a/Lib/test/test_asyncio/test_sslproto.py
+++ b/Lib/test/test_asyncio/test_sslproto.py
@@ -109,6 +109,54 @@ class SslProtoHandshakeTests(test_utils.TestCase):
test_utils.run_briefly(self.loop)
self.assertIsInstance(waiter.exception(), ConnectionAbortedError)
+ def test_connection_lost_when_busy(self):
+ # gh-118950: SSLProtocol.connection_lost not being called when OSError
+ # is thrown on asyncio.write.
+ sock = mock.Mock()
+ sock.fileno = mock.Mock(return_value=12345)
+ sock.send = mock.Mock(side_effect=BrokenPipeError)
+
+ # construct StreamWriter chain that contains loop dependant logic this emulates
+ # what _make_ssl_transport() does in BaseSelectorEventLoop
+ reader = asyncio.StreamReader(limit=2 ** 16, loop=self.loop)
+ protocol = asyncio.StreamReaderProtocol(reader, loop=self.loop)
+ ssl_proto = self.ssl_protocol(proto=protocol)
+
+ # emulate reading decompressed data
+ sslobj = mock.Mock()
+ sslobj.read.side_effect = ssl.SSLWantReadError
+ sslobj.write.side_effect = ssl.SSLWantReadError
+ ssl_proto._sslobj = sslobj
+
+ # emulate outgoing data
+ data = b'An interesting message'
+
+ outgoing = mock.Mock()
+ outgoing.read = mock.Mock(return_value=data)
+ outgoing.pending = len(data)
+ ssl_proto._outgoing = outgoing
+
+ # use correct socket transport to initialize the SSLProtocol
+ self.loop._make_socket_transport(sock, ssl_proto)
+
+ transport = ssl_proto._app_transport
+ writer = asyncio.StreamWriter(transport, protocol, reader, self.loop)
+
+ async def main():
+ # writes data to transport
+ async def write():
+ writer.write(data)
+ await writer.drain()
+
+ # try to write for the first time
+ await write()
+ # try to write for the second time, this raises as the connection_lost
+ # callback should be done with error
+ with self.assertRaises(ConnectionResetError):
+ await write()
+
+ self.loop.run_until_complete(main())
+
def test_close_during_handshake(self):
# bpo-29743 Closing transport during handshake process leaks socket
waiter = self.loop.create_future()
diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-05-12-03-10-36.gh-issue-118950.5Wc4vp.rst b/Misc/NEWS.d/next/Core and Builtins/2024-05-12-03-10-36.gh-issue-118950.5Wc4vp.rst
new file mode 100644
index 0000000..82be975
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2024-05-12-03-10-36.gh-issue-118950.5Wc4vp.rst
@@ -0,0 +1 @@
+Fix bug where SSLProtocol.connection_lost wasn't getting called when OSError was thrown on writing to socket.