warmcat / libwebsockets

canonical libwebsockets.org networking library
https://libwebsockets.org
Other
4.78k stars 1.49k forks source link

Issue with selecting appropriate websocket subprotocol in client #2795

Open mfmayer opened 1 year ago

mfmayer commented 1 year ago

When connecting to a websocket server, the client can provide multiple supported subprotocols in the header Sec-Websocket-Protocol. The server then chooses one of them and returns the chosen with the same header Sec-Websocket-Protocol.

In https://github.com/warmcat/libwebsockets/blob/ec6d5ac6d58d92ac8c1a3d769d076cabd6aa4ac1/lib/roles/ws/client-ws.c#L385

    /* keep client connection pre-bound protocol */
    if (!lwsi_role_client(wsi))
        wsi->a.protocol = NULL;

    while (n < wsi->a.vhost->count_protocols) {
        if (!wsi->a.protocol &&
            strcmp(p, wsi->a.vhost->protocols[n].name) == 0) {
            wsi->a.protocol = &wsi->a.vhost->protocols[n];
            break;
        }
        n++;
    }

the client goes through the known protocols but will never assign the correct one, because there is always a pre-bound one, because in https://github.com/warmcat/libwebsockets/blob/ec6d5ac6d58d92ac8c1a3d769d076cabd6aa4ac1/lib/core-net/client/connect.c#L295 it always assigns per default the first one.

If this is intended, I wonder how I can then find out which protocol the server and client have agreed upon and how I'm supposed to use the correct protocol in the client.

ljluestc commented 1 year ago

You can modify the code to ensure that the correct protocol is assigned when the server and client agree on a protocol. Here's an updated version of the code snippet:


/* keep client connection pre-bound protocol */
if (!lwsi_role_client(wsi))
    wsi->a.protocol = NULL;

while (n < wsi->a.vhost->count_protocols) {
    if (strcmp(p, wsi->a.vhost->protocols[n].name) == 0) {
        wsi->a.protocol = &wsi->a.vhost->protocols[n];
        break;
    }
    n++;
}

if (!wsi->a.protocol)
    wsi->a.protocol = &wsi->a.vhost->protocols[0];

remove the condition if (!wsi->a.protocol) from the loop. Instead, assign the default protocol only if no matching protocol is found. This ensures that if a matching protocol is found in the loop, it will be assigned to wsi->a.protocol

tomomomo0000 commented 5 months ago

Hi. I am facing the same problem. I am unable to modify the source code of the libwebsocket library in my environment.

Therefore, I would like to know how to get the name of the subprotocol selected at the time of connection on the client side. Could you please let us know if there is a way to do that?

I look forward to hearing from you.