Skip to content
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

Expose Sec-WebSocket-Protocol header value when present #760

Open
pfernie opened this issue Dec 3, 2020 · 5 comments
Open

Expose Sec-WebSocket-Protocol header value when present #760

pfernie opened this issue Dec 3, 2020 · 5 comments
Labels
feature New feature or request

Comments

@pfernie
Copy link

pfernie commented Dec 3, 2020

This issue is related to #496, although the use case is slightly more general.

Currently, as documented in that issue, warp handles the WebSocket upgrade statically, and elides any handling of a Sec-WebSocket-Protocol header. A workaround used in #496 and similarly in async-graphql's warp integration is to manually set this header in the response to the assumed protocol (e.g. graphql-ws).

With the recent revision of the GraphQL Over WebSockets "spec", the situation is further complicated. The name of the protocol was changed; from the old de facto standard established by subscriptions-transport-ws the subprotocol was named graphql-ws. With the revised graphql-ws, this is (confusingly) renamed graphql-transport-ws. But beyond wanting to reply with the same protocol as the client set in the Sec-WebSocket-Protocol header of the initial GET request, the new graphql-ws protocol differs slightly from the previous subscriptions-transport-ws, and as such servers wanting to support both legacy and newer clients need to act (change logic) accordingly.

Some solutions which would facilitate this are:

  • If filters::ws::Ws exposed a new field protocol similar to the existing key. The headers crate does not seem to provide a typed SecWebSocketProtocol akin to SecWebSocketKey, so either this would be protocol: Option<String>, or support in headers could be added. Per RFC6455, it seems the Sec-WebSocket-Protocol header is optional.
  • Alternatively, the entire set of headers could be provided as a field, akin to the existing field body.

EDIT:
Per the RFC, the header may specify multiple supported protocols, so protocol would more appropriately be Option<Vec<String>>, or simply Vec<String> if there is no semantic use to distinguishing empty header from non-present header.

@seanmonstar
Copy link
Owner

It's probably worth pointing out that this can be done already, it just isn't part of the Ws type.

warp::ws()
    .and(warp::headers::value("sec-websocket-protocol"))
    .and_then(|ws, proto| {
        let reply = ws.on_upgrade(something_with_websocket);
        Ok(warp::reply::with_header(reply, "sec-websocket-protocol", proto))
    })

@pfernie
Copy link
Author

pfernie commented Dec 3, 2020

Thanks, that is a straightforward solution indeed!

@benitogf
Copy link

the headers filters moved, updated solution:

warp::ws()
    .and(warp::filters::header::value("sec-websocket-protocol"))
    .and_then(|ws, proto| {
        let reply = ws.on_upgrade(something_with_websocket);
        Ok(warp::reply::with_header(reply, "sec-websocket-protocol", proto))
    })

@thewh1teagle
Copy link

thewh1teagle commented Oct 25, 2023

Is there a way to allow both connections which sent with sec-websocket-protocl but also connections which made without this header?

Because I think that warp::filters::header::value("sec-websocket-protocol") allow only connections which has this header

@thewh1teagle
Copy link

 let app = warp::path("ws")
        // The `ws()` filter will prepare Websocket handshake...
        .and(warp::ws())
        .and(warp::header::optional::<String>("sec-websocket-protocol"))
        .and(users)
        .map(|ws: warp::ws::Ws, maybe_proto: Option<String>, users| {
            // This will call our function if the handshake succeeds.
            let reply = ws.on_upgrade(move |socket| user_connected(socket, users));
            if let Some(proto) = maybe_proto {
                return warp::reply::with_header(reply, "sec-websocket-protocol", proto)
            }
            return warp::reply::with_header(reply, "", "");
        });

Maybe something like that, not sure. it force me to reply with header eventually

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature New feature or request
Projects
None yet
Development

No branches or pull requests

4 participants