skaarj1989 / mWebSockets

WebSockets for microcontrollers
https://skaarj1989.github.io/mWebSockets/autobahn-testsuite/servers/
MIT License
108 stars 23 forks source link

Feature request: subprotocol negotiation API #38

Closed fkromer closed 3 years ago

fkromer commented 3 years ago

I've not found something related to subprotocol negotiation in the sources. Is mWebSockets supporting it already? In case not you could of course expect either contribution or sponsoring (if this is an option for you).

skaarj1989 commented 3 years ago

It's just a proposal draft of what I might do.

Client: add additional parameter in open(), an array of subprotocols:

WebSocketClient client;
const char *supportedProtocols[] = {"soap", "wamp", nullptr};
client.open("...", 3000, "/", supportedProtocols);
// The client will send:
// Sec-WebSocket-Protocol: soap, wamp

Server: add callback

WebSocketServer server(3000);
server.setProtocolHandler([](const char **protocols) {
  // In this callback you are supposed to negotiate the subprotocol and return its name
  // (or nullptr on fail)

  // Iterate the list of protocols sent by the client
  for (int i = 0;; ++i) {
    const auto &protocol = protocols[i];
    if (protocol == nullptr) break;

    // The server will send: Sec-WebSocket-Protocol: soap
    if (strcmp(protocol, "soap") == 0) return "soap";
  }
  return nullptr; // supported protocol not found, terminates connection
});
fkromer commented 3 years ago

I've not looked into implementations of other libs yet. Nevertheless... your idea sounds reasonable.

fkromer commented 3 years ago

Without investing too much time I was able to find the relevant sources in Pythons websockets. The utility function verifying the subprotocols is /src/websockets/client.py#L243-L274. It checks the subprotocols in the response header. The verification is called in the client code in src/websockets/client.py#L169 as well as in the server code in src/websockets/server.py#L229. In both cases (client as well as server) the function is triggered after a handshake request has been received.

fkromer commented 3 years ago

In case of Pythons websockets the subprotocols may be defined API-wise via the client connection class instance constructor as well as the server class instance constructur.

skaarj1989 commented 3 years ago

Initial implementation for subprotocol negotiation has been uploaded to master branch. Instead of array of values I decided to use comma separated values.

Client side:

WebSocketClient client;
client.open("192.168.46.31", 3000, "/", "foo,bar,baz");
const auto protocol = client.getProtocol();
if (protocol) {
  // do something about it ...
}

Additionally, you have an option to query protocol straight out of a WebSocket via getProtocol() (might return nullptr)

Server side:

WebSocketServer server{3000};
wss.begin(nullptr, [](const char *protocols) {
  // Iterate csv with strtok or whatever you like ...
  // ...

  return "foo";
});

wss.onConnection([](WebSocket &ws) {
  const auto protocol = ws.getProtocol();
  if (protocol) {
    // whatever ...
  }
  // connect callbacks ...
});
fkromer commented 3 years ago

Wow, great. Thanks a lot.

stale[bot] commented 3 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.