Skip to content

Commit 54e13b0

Browse files
bdracowebknjaz
andauthored
Fix blocking I/O in the event loop while processing files in a post request (#8283)
Co-authored-by: Sviatoslav Sydorenko (Святослав Сидоренко) <[email protected]>
1 parent 012f986 commit 54e13b0

File tree

3 files changed

+17
-6
lines changed

3 files changed

+17
-6
lines changed

CHANGES/8283.bugfix.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fixed blocking I/O in the event loop while processing files in a POST request
2+
-- by :user:`bdraco`.

aiohttp/test_utils.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -537,8 +537,15 @@ def make_mocked_request(
537537
"""
538538
task = mock.Mock()
539539
if loop is ...:
540-
loop = mock.Mock()
541-
loop.create_future.return_value = ()
540+
# no loop passed, try to get the current one if
541+
# its is running as we need a real loop to create
542+
# executor jobs to be able to do testing
543+
# with a real executor
544+
try:
545+
loop = asyncio.get_running_loop()
546+
except RuntimeError:
547+
loop = mock.Mock()
548+
loop.create_future.return_value = ()
542549

543550
if version < HttpVersion(1, 1):
544551
closing = True

aiohttp/web_request.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -724,19 +724,21 @@ async def post(self) -> "MultiDictProxy[Union[str, bytes, FileField]]":
724724
# https://tools.ietf.org/html/rfc7578#section-4.4
725725
if field.filename:
726726
# store file in temp file
727-
tmp = tempfile.TemporaryFile()
727+
tmp = await self._loop.run_in_executor(
728+
None, tempfile.TemporaryFile
729+
)
728730
chunk = await field.read_chunk(size=2**16)
729731
while chunk:
730732
chunk = field.decode(chunk)
731-
tmp.write(chunk)
733+
await self._loop.run_in_executor(None, tmp.write, chunk)
732734
size += len(chunk)
733735
if 0 < max_size < size:
734-
tmp.close()
736+
await self._loop.run_in_executor(None, tmp.close)
735737
raise HTTPRequestEntityTooLarge(
736738
max_size=max_size, actual_size=size
737739
)
738740
chunk = await field.read_chunk(size=2**16)
739-
tmp.seek(0)
741+
await self._loop.run_in_executor(None, tmp.seek, 0)
740742

741743
if field_ct is None:
742744
field_ct = "application/octet-stream"

0 commit comments

Comments
 (0)