I am trying to figure out the maximum file size, my client can upload , so that my python fastapi server can handle it without any problem.
Your request doesn't reach the ASGI app directly. It goes through reverse proxy (Nginx, Apache), ASGI server (uvicorn, hypercorn, gunicorn) before handled by an ASGI app.
Reverse Proxy
For Nginx, the body size is controlled by client_max_body_size
, which defaults to 1MB.
For Apache, the body size could be controlled by LimitRequestBody
, which defaults to 0.
ASGI Server
The ASGI servers don't have a limit of the body size. At least it's the case for gunicorn, uvicorn, hypercorn.
Quote from Hypercorn doc.
Large request body
This attack is of the second type and aims to exhaust the server’s memory by inviting it to receive a large request body (and hence write the body to memory). A poorly configured server would have no limit on the request body size and potentially allow a single request to exhaust the server.
It is up to the framework to guard against this attack. This is to allow the framework to consume the request body if desired.
Note: Gunicorn doesn't limit the size of request body, but sizes of the request line and request header.
--limit-request-line
, size limit on each req line, default 4096--limit-request-fields
, number of header fields, default 100--limit-request-field_size
, size of headef fields, default 8190
ASGI App/Framework
Since FastAPI is based upon Starlette. How to reading the body is handled by Starlette. Reading from the source (0.14.3), there seems no limit on request body either.
class Request(HTTPConnection):
...
async def stream(self) -> typing.AsyncGenerator[bytes, None]:
if hasattr(self, "_body"):
yield self._body
yield b""
return
if self._stream_consumed:
raise RuntimeError("Stream consumed")
self._stream_consumed = True
while True:
message = await self._receive()
if message["type"] == "http.request":
body = message.get("body", b"")
if body:
yield body
if not message.get("more_body", False):
break
elif message["type"] == "http.disconnect":
self._is_disconnected = True
raise ClientDisconnect()
yield b""
async def body(self) -> bytes:
if not hasattr(self, "_body"):
chunks = []
async for chunk in self.stream():
chunks.append(chunk)
self._body = b"".join(chunks)
return self._body
Conclusion: If you get 413 Payload Too Large error, check the reverse proxy.
© 2022 - 2024 — McMap. All rights reserved.
Content-Length
header – Potted.stream()
, and hence, enforce body/file size limits in your application. – Undersexed