h2
h2 copied to clipboard
Support WebSocket upgrade
RFC 8441 specifies the upgrade mechanism to WebSocket over HTTP/2. Since it includes several extensions to the HTTP/2 protocol, the server API might need to support the configuration of them.
Would you be able to provide a summary of the ways in which h2 needs to change to support this use case?
Here is a summary of RFC:
- Adds a new SETTINGS parameter
SETTINGS_ENABLE_CONNECT_PROTOCOL(=0x8) is added[^1]. The server sends this parameter with the value1at the beginning of connection. - The handshake request uses CONNECT method instead of GET [^2]. The header fields used for handshaking are similar to the current WebSocket spec, but several pseudo-header been added or removed.
- After the request is upgraded, the payloads are send and received via DATA frame.
[^1] : https://tools.ietf.org/html/rfc8441#section-3 [^2] : https://tools.ietf.org/html/rfc8441#section-4
Seems plausible. I wonder if we need to add support for that specific settings option or we can extend h2 to allow for configurable settings.
I've been looking into this. Adding SETTINGS_ENABLE_CONNECT_PROTOCOL is straightforward but I'm stuck on exposing the :protocol pseudo-header.
The client needs to send it, the server needs to receive it, but I can't pass it through http::Request because it's not a legal traditional HTTP header. Suggestions on how to proceed welcome.
Hm, ya... The first thing that comes to my mind is to store some h2::Something type in the Request::extensions() indicating a :protocol pseudo header. Does that work cleanly? Should it?
I had the same thought and have a local prototype that adds a pub fn websocket(req: &mut Request<()>) { /* ... */ } that does that (but probably needs a better name.)
It feels kind of icky for reasons I can't quite articulate though. :-)
Is it feasible to add the pseudo header information to the RecvStream?
Is there any way I can help? I would appreciate if we can implement this, so I can use WebSockets on HTTP/2 :)
I believe this was largely done by @nox in #565 a year ago. Anything missing? It looks like h2::ext::Protocol is not added as extension to the Request, at least I don't see it even though tracing shows that h2 received headers containing the :protocol pseudo header (set to b"websocket" in my case).
The server tests don't seem to cover this.
https://github.com/hyperium/h2/blob/07d20b19abfd3bf57bd80976089e3c24a3166bca/tests/h2-tests/tests/server.rs
I was hoping for an example that shows how one can check for "the-bread-protocol" on the server side.
I added the following code to server::Peer::convert_poll_message() and that exposes the protocol as Request extension. This works for me. Not sure if this is the right place to do this, though.
if let Some(p) = pseudo.protocol {
if let Some(exts) = b.extensions_mut() {
exts.insert(p);
}
}
https://github.com/hyperium/h2/blob/07d20b19abfd3bf57bd80976089e3c24a3166bca/src/server.rs#L1427-L1535