From f512095275bdec5b9775eaa7d6a04149baee7b31 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 2 Apr 2024 09:33:43 -1000 Subject: [PATCH 1/4] Fix blocking I/O in the event loop while processing files in a post request --- aiohttp/test_utils.py | 7 +++++-- aiohttp/web_request.py | 10 ++++++---- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/aiohttp/test_utils.py b/aiohttp/test_utils.py index 83d7671b6b1..853fc74cade 100644 --- a/aiohttp/test_utils.py +++ b/aiohttp/test_utils.py @@ -537,8 +537,11 @@ def make_mocked_request( """ task = mock.Mock() if loop is ...: - loop = mock.Mock() - loop.create_future.return_value = () + try: + loop = asyncio.get_running_loop() + except RuntimeError: + loop = mock.Mock() + loop.create_future.return_value = () if version < HttpVersion(1, 1): closing = True diff --git a/aiohttp/web_request.py b/aiohttp/web_request.py index 5402dadf30c..1945db3b224 100644 --- a/aiohttp/web_request.py +++ b/aiohttp/web_request.py @@ -724,19 +724,21 @@ async def post(self) -> "MultiDictProxy[Union[str, bytes, FileField]]": # https://tools.ietf.org/html/rfc7578#section-4.4 if field.filename: # store file in temp file - tmp = tempfile.TemporaryFile() + tmp = await self._loop.run_in_executor( + None, tempfile.TemporaryFile + ) chunk = await field.read_chunk(size=2**16) while chunk: chunk = field.decode(chunk) - tmp.write(chunk) + await self._loop.run_in_executor(None, tmp.write, chunk) size += len(chunk) if 0 < max_size < size: - tmp.close() + await self._loop.run_in_executor(None, tmp.close) raise HTTPRequestEntityTooLarge( max_size=max_size, actual_size=size ) chunk = await field.read_chunk(size=2**16) - tmp.seek(0) + await self._loop.run_in_executor(None, tmp.seek, 0) if field_ct is None: field_ct = "application/octet-stream" From 82b04b23f106516013dbfc8b76c678e207eaa1be Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 2 Apr 2024 10:07:16 -1000 Subject: [PATCH 2/4] timeline --- CHANGES/8283.bugfix.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 CHANGES/8283.bugfix.rst diff --git a/CHANGES/8283.bugfix.rst b/CHANGES/8283.bugfix.rst new file mode 100644 index 00000000000..a0cd2be0e90 --- /dev/null +++ b/CHANGES/8283.bugfix.rst @@ -0,0 +1,2 @@ +Fix blocking I/O in the event loop while processing files in a post request +-- by :user:`bdraco`. From 268bb36637d4a21f30472cc657c57c32e2337fc0 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 3 Apr 2024 07:03:34 -1000 Subject: [PATCH 3/4] Update CHANGES/8283.bugfix.rst MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sviatoslav Sydorenko (Святослав Сидоренко) --- CHANGES/8283.bugfix.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES/8283.bugfix.rst b/CHANGES/8283.bugfix.rst index a0cd2be0e90..d456d59ba8e 100644 --- a/CHANGES/8283.bugfix.rst +++ b/CHANGES/8283.bugfix.rst @@ -1,2 +1,2 @@ -Fix blocking I/O in the event loop while processing files in a post request +Fixed blocking I/O in the event loop while processing files in a POST request -- by :user:`bdraco`. From 9fd76882de2a9eefd8d4284671dd3556694a9d36 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 3 Apr 2024 07:06:55 -1000 Subject: [PATCH 4/4] add comment --- aiohttp/test_utils.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/aiohttp/test_utils.py b/aiohttp/test_utils.py index 853fc74cade..544cdf84a55 100644 --- a/aiohttp/test_utils.py +++ b/aiohttp/test_utils.py @@ -537,6 +537,10 @@ def make_mocked_request( """ task = mock.Mock() if loop is ...: + # no loop passed, try to get the current one if + # its is running as we need a real loop to create + # executor jobs to be able to do testing + # with a real executor try: loop = asyncio.get_running_loop() except RuntimeError: