]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
GH-110894: Call loop exception handler for exceptions in client_connected_cb (#111601)
authorKumar Aditya <kumaraditya@python.org>
Thu, 2 Nov 2023 07:38:18 +0000 (13:08 +0530)
committerGitHub <noreply@github.com>
Thu, 2 Nov 2023 07:38:18 +0000 (07:38 +0000)
Call loop exception handler for exceptions in `client_connected_cb` of `asyncio.start_server` so that applications can handle it.

Lib/asyncio/streams.py
Lib/test/test_asyncio/test_streams.py
Misc/NEWS.d/next/Library/2023-11-01-14-03-24.gh-issue-110894.7-wZxC.rst [new file with mode: 0644]

index bc84e53b8443cf48316cf15ec1d65bd71c46493e..f82b10c3803656c81c12361b04c319bb7926addb 100644 (file)
@@ -245,7 +245,19 @@ class StreamReaderProtocol(FlowControlMixin, protocols.Protocol):
             res = self._client_connected_cb(reader,
                                             self._stream_writer)
             if coroutines.iscoroutine(res):
+                def callback(task):
+                    exc = task.exception()
+                    if exc is not None:
+                        self._loop.call_exception_handler({
+                            'message': 'Unhandled exception in client_connected_cb',
+                            'exception': exc,
+                            'transport': transport,
+                        })
+                        transport.close()
+
                 self._task = self._loop.create_task(res)
+                self._task.add_done_callback(callback)
+
             self._strong_reader = None
 
     def connection_lost(self, exc):
index 9c92e75886c593beb0119115de4f8c9728f2f2fb..c477b6c838c5e06209f31bea74ccba939d4c7c64 100644 (file)
@@ -1096,6 +1096,34 @@ os.close(fd)
 
         self.assertEqual(messages, [])
 
+    def test_unhandled_exceptions(self) -> None:
+        port = socket_helper.find_unused_port()
+
+        messages = []
+        self.loop.set_exception_handler(lambda loop, ctx: messages.append(ctx))
+
+        async def client():
+            rd, wr = await asyncio.open_connection('localhost', port)
+            wr.write(b'test msg')
+            await wr.drain()
+            wr.close()
+            await wr.wait_closed()
+
+        async def main():
+            async def handle_echo(reader, writer):
+                raise Exception('test')
+
+            server = await asyncio.start_server(
+                handle_echo, 'localhost', port)
+            await server.start_serving()
+            await client()
+            server.close()
+            await server.wait_closed()
+
+        self.loop.run_until_complete(main())
+
+        self.assertEqual(messages[0]['message'],
+                         'Unhandled exception in client_connected_cb')
 
 
 if __name__ == '__main__':
diff --git a/Misc/NEWS.d/next/Library/2023-11-01-14-03-24.gh-issue-110894.7-wZxC.rst b/Misc/NEWS.d/next/Library/2023-11-01-14-03-24.gh-issue-110894.7-wZxC.rst
new file mode 100644 (file)
index 0000000..c59fe6b
--- /dev/null
@@ -0,0 +1 @@
+Call loop exception handler for exceptions in ``client_connected_cb`` of :func:`asyncio.start_server` so that applications can handle it. Patch by Kumar Aditya.