From bacbe5d4bb58dfd405e3f331976137e64b96c6c8 Mon Sep 17 00:00:00 2001 From: Olivier Gayot Date: Thu, 14 Apr 2022 15:05:19 +0200 Subject: [PATCH] drivers: prevent client crash if GET /drivers is closed from client side When a HTTP client sends a query but closes the socket before an answer is received, aiohttp signals it on the server end by raising an asyncio.CancelledError in the associated query handler. By default, when a task is cancelled with asyncio, the task(s) that it is currently awaiting on are cancelled as well. The GET handler for /drivers?wait=true awaits on the "list drivers" task. Therefore, if the GET handler gets cancelled, so will be the "list drivers" task. When that happens, any subsequent call to GET /drivers?wait=true will make the server raise an asyncio.CancelledError because the "list drivers" task has already been cancelled. This results in: * the socket being closed from the server end * an aiohttp.client_exceptions.ServerDisconnectedError exception raised on the client end. This type of exception is unhandled and makes the client crash. Fixed by preventing the "list drivers" task from being cancelled when the GET /drivers query handler gets cancelled. https://bugs.launchpad.net/subiquity/+bug/1968729 Signed-off-by: Olivier Gayot --- subiquity/server/controllers/drivers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subiquity/server/controllers/drivers.py b/subiquity/server/controllers/drivers.py index ed6d9468..96e6285d 100644 --- a/subiquity/server/controllers/drivers.py +++ b/subiquity/server/controllers/drivers.py @@ -91,7 +91,7 @@ class DriversController(SubiquityController): async def GET(self, wait: bool = False) -> DriversResponse: if wait: - await self._drivers_task + await asyncio.shield(self._drivers_task) return DriversResponse(install=self.model.do_install, drivers=self.drivers)