Skip to content

Commit

Permalink
Fix blocking I/O in the event loop while processing files in a post r…
Browse files Browse the repository at this point in the history
…equest (#8283)

Co-authored-by: Sviatoslav Sydorenko (Святослав Сидоренко) <[email protected]>
  • Loading branch information
bdraco and webknjaz authored Apr 5, 2024
1 parent 012f986 commit 54e13b0
Show file tree
Hide file tree
Showing 3 changed files with 17 additions and 6 deletions.
2 changes: 2 additions & 0 deletions CHANGES/8283.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Fixed blocking I/O in the event loop while processing files in a POST request
-- by :user:`bdraco`.
11 changes: 9 additions & 2 deletions aiohttp/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -537,8 +537,15 @@ def make_mocked_request(
"""
task = mock.Mock()
if loop is ...:
loop = mock.Mock()
loop.create_future.return_value = ()
# 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:
loop = mock.Mock()
loop.create_future.return_value = ()

if version < HttpVersion(1, 1):
closing = True
Expand Down
10 changes: 6 additions & 4 deletions aiohttp/web_request.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down

0 comments on commit 54e13b0

Please sign in to comment.