-
-
Notifications
You must be signed in to change notification settings - Fork 931
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add RequestSizeLimitMiddleware and RequestTimeoutMiddleware #2328
base: master
Are you sure you want to change the base?
Conversation
TODOs:
|
A couple of things to consider:
|
Both middlewares can be on a third party packages, and we can close the issue by just pointing at them. Can we separate the two middlewares in different PRs? The initial discussion was about the request size one. |
I disagree. It's an important feature to have readily available to all Starlette users, it doesn't require 3rd party packages, the complexity isn't massive and I believe we should make some limits the default in 1.0 like Django and other more mature frameworks do.
Yes I'm happy to do that if it'd make it easier to discuss. |
for reference: my approach which works on per-route basis |
My main concern about middleware based approach is that it is very limited. Say, your global middleware will always have a large value. Because if just one route needs to handle 1gb uploads, the global limit will be 1gb. I see it as app-level limit (the global one that covers all middlewares also) + option to override per a route. In result, we can get this example setup: 8mb global and 24mb for |
Yeah, I brought that up above. I'll rework this to satisfy that use case, although it will be a good chunk more invasive as I said above. |
Also sorry I did not consider your PR, I had lost track / forgotten about it. |
I have a small question, why not just read the request content-length to limit the size. |
Clients can easily lie about that |
But proxy server or asgi |
I'm not saying we shouldn't also limit the length to the reported content length, I'm just saying that it doesn't serve a security purpose. |
Maybe my previous words caused some misunderstanding. What I meant was: the forward reverse proxy server or ASGI server will not pass data to the ASGI application that exceeds the content-length length. Therefore, forging a content-length length on the client side will only result in truncation when the server receives data. |
Then I’m confused as to what you are suggesting: are you saying that we should also enforce that limit, that that limit is already enforced elsewhere, and this PR (or #2174) is not needed, or something else? |
async def rcv() -> Message: | ||
nonlocal total_size | ||
message = await receive() | ||
chunk_size = len(message.get("body", b"")) | ||
if self.max_chunk_size is not None and chunk_size > self.max_chunk_size: | ||
raise ChunkTooLarge( | ||
self.max_chunk_size | ||
if self.include_limits_in_error_responses | ||
else None | ||
) | ||
total_size += chunk_size | ||
if self.max_request_size is not None and total_size > self.max_request_size: | ||
raise RequestTooLarge( | ||
self.max_request_size | ||
if self.include_limits_in_error_responses | ||
else None | ||
) | ||
return message |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then I’m confused as to what you are suggesting: are you saying that we should also enforce that limit, that that limit is already enforced elsewhere, and this PR (or #2174) is not needed, or something else?
Would it be more concise and efficient to change here to judge the request content-length?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of the user-defined limits? Or in addition to?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What @abersheeran meant is to check the Content-Length
instead of having the logic of adding up chunk_size
s - which is actually what Django does: https://github.com/django/django/blob/6daf86058bb6fb922eb3fe3abae6f5c0e645020c/django/http/request.py#L323-L347.
Django also has this logic on the multipart parser: https://github.com/django/django/blob/594873befbbec13a2d9a048a361757dd3cf178da/django/http/multipartparser.py#L241-L248.
I don't think WebSockets should be a point of concern here.
Nothing to do for lifespans.
No special logic is required for SSE. Notes/Questions
|
The configurations offered by Uvicorn don't cover all of the use cases here. You can't configure it on a per route basis for starters.
What I mean is that if you install a blanket timeout or request size limit it might make sense to say "SSE requests don't have a limit". That would require special logic.
Yes.
Agreed, we can check it and if it is larger than the limit error immediately without streaming anything. But we can't "trust" it if it's smaller. |
We can trust the content length header. The server errors otherwise. |
But Starlette doesn't depend on the server. We shouldn't make assumptions like this about the server's behavior unless it's part of the ASGI spec, which to my knowledge this is not. Besides, the only advantage of trusting the |
Closes #2155