]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.12] gh-118950: Fix SSLProtocol.connection_lost not being called when OSError is...
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Sat, 26 Oct 2024 16:32:07 +0000 (18:32 +0200)
committerGitHub <noreply@github.com>
Sat, 26 Oct 2024 16:32:07 +0000 (22:02 +0530)
gh-118950: Fix SSLProtocol.connection_lost not being called when OSError is thrown (GH-118960)

(cherry picked from commit 3f24bde0b6689b8f05872a8118a97908b5a94659)

Co-authored-by: Javad Shafique <javadshafique@hotmail.com>
Co-authored-by: Kumar Aditya <kumaraditya@python.org>
Lib/asyncio/sslproto.py
Lib/test/test_asyncio/test_sslproto.py
Misc/NEWS.d/next/Core and Builtins/2024-05-12-03-10-36.gh-issue-118950.5Wc4vp.rst [new file with mode: 0644]

index e51669a2ab2af6d882f74423c4e69a51c4b67406..29e72b1fd9aa24c76fb7795e0addd1a1bcb248d6 100644 (file)
@@ -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.
 
index f5f0afeab51c9e9de865481ac2b6b3a585070353..761904c5146b6a9eb1abc298b9b042677fb9f788 100644 (file)
@@ -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 (file)
index 0000000..82be975
--- /dev/null
@@ -0,0 +1 @@
+Fix bug where SSLProtocol.connection_lost wasn't getting called when OSError was thrown on writing to socket.