Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 20 additions & 6 deletions aiohttp/web_request.py
Original file line number Diff line number Diff line change
Expand Up @@ -740,17 +740,31 @@ async def post(self) -> "MultiDictProxy[str | bytes | FileField]":
out.add(field.name, ff)
else:
# deal with ordinary data
value = await field.read(decode=True)
raw_data = bytearray()
# Test the raw size, but only add to the overall size on decode
encoded_size = size
while chunk := await field.read_chunk():
encoded_size += len(chunk)
if 0 < max_size < encoded_size:
raise HTTPRequestEntityTooLarge(
max_size=max_size, actual_size=encoded_size
)
raw_data.extend(chunk)

value = bytearray()
async for d in field.decode_iter(raw_data):
size += len(d)
if 0 < max_size < size:
raise HTTPRequestEntityTooLarge(
max_size=max_size, actual_size=size
)
value.extend(d)

if field_ct is None or field_ct.startswith("text/"):
charset = field.get_charset(default="utf-8")
out.add(field.name, value.decode(charset))
else:
out.add(field.name, value)
size += len(value)
if 0 < max_size < size:
raise HTTPRequestEntityTooLarge(
max_size=max_size, actual_size=size
)
else:
raise ValueError(
"To decode nested multipart you need to use custom reader",
Expand Down
30 changes: 29 additions & 1 deletion tests/test_web_functional.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import asyncio
import gzip
import io
import json
import pathlib
Expand All @@ -25,7 +26,12 @@
)
from aiohttp.abc import AbstractResolver, ResolveResult
from aiohttp.compression_utils import ZLibBackend, ZLibCompressObjProtocol
from aiohttp.hdrs import CONTENT_LENGTH, CONTENT_TYPE, TRANSFER_ENCODING
from aiohttp.hdrs import (
CONTENT_ENCODING,
CONTENT_LENGTH,
CONTENT_TYPE,
TRANSFER_ENCODING,
)
from aiohttp.pytest_plugin import AiohttpClient, AiohttpServer
from aiohttp.typedefs import Handler, Middleware
from aiohttp.web_protocol import RequestHandler
Expand Down Expand Up @@ -1700,6 +1706,28 @@ async def handler(request: web.Request) -> NoReturn:
assert "Maximum request body size 1048576 exceeded, actual body size" in resp_text


async def test_app_max_client_size_form_decode(aiohttp_client: AiohttpClient) -> None:
async def handler(request: web.Request) -> NoReturn:
await request.post()
assert False

app = web.Application()
app.router.add_post("/", handler)
client = await aiohttp_client(app)

with aiohttp.MultipartWriter("form-data") as mp:
# Verify that entire multipart form can't exceed client size (not just each field).
for i in range(3):
part = mp.append(gzip.compress(b"A" * 512000))
part.set_content_disposition("form-data", name=f"f{i}")
part.headers[CONTENT_ENCODING] = "gzip"

async with client.post("/", data=mp) as resp:
assert resp.status == 413
resp_text = await resp.text()
assert "Maximum request body size 1048576 exceeded, actual body size" in resp_text


async def test_app_max_client_size_adjusted(aiohttp_client: AiohttpClient) -> None:
async def handler(request: web.Request) -> web.Response:
await request.post()
Expand Down
Loading