Skip to content

Support the WebSocket Denial Response ASGI extension#1916

Merged
Kludex merged 23 commits intoKludex:masterfrom
kristjanvalur:kristjan/ext
Dec 17, 2023
Merged

Support the WebSocket Denial Response ASGI extension#1916
Kludex merged 23 commits intoKludex:masterfrom
kristjanvalur:kristjan/ext

Conversation

@kristjanvalur
Copy link
Copy Markdown
Contributor

@kristjanvalur kristjanvalur commented Mar 29, 2023

uvicorn now can return a response from websocket apps that choose to reject a connection with a custom response.
See https://github.com/encode/starlette/pull/2041/files for related work.

This is a re-submission of pr #1907

Comment thread uvicorn/protocols/websockets/wsproto_impl.py Outdated
@Kludex
Copy link
Copy Markdown
Owner

Kludex commented Mar 29, 2023

still something broken with the GHA. I'll leave this until we sort out what's going on.

It looks like it's related to this PR. I just cancelled the two previous jobs.

Comment thread tests/protocols/test_websocket.py Outdated
Comment on lines +1128 to +1172
if ws_protocol_cls == WSProtocol:
# wsproto automatically makes the message chunked
assert response.headers["transfer-encoding"] == "chunked"
else:
# websockets automatically adds a content-length
assert response.headers["content-length"] == "8"
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It makes sense for WebSockets to add the content-length, since we can't have a chunked one there.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

well, this is only about what happens if the app doesn't provide a content-length and only provides the raw body data. the defaults for these two protocols are different. Technically, you can provide chunked data over the websockets: The app, provides the "chunked" header, and then provides the chunks, with the appropriate chunk headers (as an application should do if it provides that header (I think). I think that nowadays it is rare for an application to specify content length or transfer encoding...

@Kludex
Copy link
Copy Markdown
Owner

Kludex commented Mar 29, 2023

Interesting... I've just found this:

The protocol server must not start sending the response to the client until it has received at least one Response Body event.

Ref.: https://asgi.readthedocs.io/en/latest/specs/www.html#response-start-send-event

Meaning that we shouldn't be sending the 404 if nobody is provided... But that also means that we have an issue with the HTTP implementations 🤔

@kristjanvalur
Copy link
Copy Markdown
Contributor Author

Meaning that we shouldn't be sending the 404 if nobody is provided... But that also means that we have an issue with the HTTP implementations 🤔

Yes, h11 definitely starts sending the header before receiving the first body.

This can be fixed, I can fix both h11 and websockets to wait for the first body... I can do it for websockets in this PR and then a followup one for h11_impl.py

@kristjanvalur
Copy link
Copy Markdown
Contributor Author

It looks like it's related to this PR. I just cancelled the two previous jobs.

Well, I haven't touched any of the .github/ code, and this is what the actions log says:
GitHub Actions has encountered an internal error when running your job.
The actions don't even start. I have never seen this before.

@kristjanvalur kristjanvalur marked this pull request as ready for review March 30, 2023 23:04
@kristjanvalur
Copy link
Copy Markdown
Contributor Author

seems things are running smoothly again. there was hanging test due to an introduced bug, but that should not have caused these weird symptoms. Now fixed.

@paulo-raca
Copy link
Copy Markdown

Awesome, thanks!

@kristjanvalur
Copy link
Copy Markdown
Contributor Author

I guess there are some changes upstream. Do you want me to update this PR?

@Kludex
Copy link
Copy Markdown
Owner

Kludex commented Dec 2, 2023

Yes. I'll get to this tomorrow.

@Kludex Kludex changed the title Support the websocket.http.response ASGI extension Support the WebSocket Denial Response ASGI extension Dec 17, 2023
Copy link
Copy Markdown
Owner

@Kludex Kludex left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kristjanvalur Please check my changes, and if we are fine, let's merge this.

Comment on lines +325 to +319
# Create the event here but do not send it, the ASGI spec
# suggest that we wait for the body event before sending.
# https://asgi.readthedocs.io/en/latest/specs/www.html#response-start-send-event
self.reject_event = event
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We already discussed this: django/asgiref#387

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know. I disagree, I think the recommendation is a good one because it enlarges the window during which the server can still send a 500 error in case the application messes up. It is not a requirement but (IMHO) good practice in a library, and that is the reason I wrote the code that way.
But it is your call of course, happy to get this merged either way.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand, and it makes sense... But I'll rather not have a mismatch in how the HTTP implementations behave, and the WebSockets.

Comment thread uvicorn/protocols/websockets/wsproto_impl.py Outdated
Comment thread uvicorn/_types.py
type: Literal["websocket.http.response.body"]
body: bytes
more_body: bool
more_body: NotRequired[bool]
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is more correct.

Copy link
Copy Markdown
Contributor Author

@kristjanvalur kristjanvalur Dec 17, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you say so :), We didn't have those fancy type decorations in the old days.

@Kludex Kludex merged commit 6568184 into Kludex:master Dec 17, 2023
@kristjanvalur kristjanvalur deleted the kristjan/ext branch December 18, 2023 09:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants