Ignore a subprotocol the WebSocket client did not offer

A SubProtocolSelector could return a value outside the client's
Sec-WebSocket-Protocol list, and the server sent it back as is. The
server now treats such a value as no selection.
This commit is contained in:
yhirose committed 2026-10-04 18:34:21 -04:00
1 parent 4fcbc08f2d
commit 6d1049462d
3 files changed
+31 -1

No files matched your search

+1 -1
View File
@@ -119,7 +119,7 @@ using SubProtocolSelector =
std::function<std::string(const std::vector<std::string> &protocols)>; std::function<std::string(const std::vector<std::string> &protocols)>;
``` ```
The `SubProtocolSelector` receives the list of subprotocols proposed by the client (from the `Sec-WebSocket-Protocol` header) and returns the selected one. Return an empty string to decline all proposed subprotocols. The `SubProtocolSelector` receives the list of subprotocols proposed by the client (from the `Sec-WebSocket-Protocol` header) and returns the selected one. Return an empty string to decline all proposed subprotocols. A returned value that the client did not propose is ignored.
### WebSocket (Server-side) ### WebSocket (Server-side)
+6
View File
@@ -14692,6 +14692,12 @@ Server::process_request(Stream &strm, const std::string &remote_addr,
protocols.emplace_back(b, e); protocols.emplace_back(b, e);
}); });
selected_subprotocol = entry.sub_protocol_selector(protocols); selected_subprotocol = entry.sub_protocol_selector(protocols);
// Ignore a selection the client did not offer (RFC 6455 4.2.2)
if (std::find(protocols.begin(), protocols.end(),
selected_subprotocol) == protocols.end()) {
selected_subprotocol.clear();
}
} }
} }
+24
View File
@@ -24061,6 +24061,18 @@ protected:
} }
return ""; return "";
}); });
server_->WebSocket(
"/ws-subprotocol-unoffered",
[](const Request &, ws::WebSocket &ws) {
std::string msg;
while (ws.read(msg)) {
ws.send(msg);
}
},
[](const std::vector<std::string> &) -> std::string {
return "admin";
});
} }
void start_server() { void start_server() {
@@ -24403,6 +24415,18 @@ TEST_F(WebSocketIntegrationTest, SubProtocolNoMatch) {
client.close(); client.close();
} }
TEST_F(WebSocketIntegrationTest, SubProtocolSelectorReturnsUnoffered) {
Headers headers = {{"Sec-WebSocket-Protocol", "chat"}};
ws::WebSocketClient client("ws://localhost:" + std::to_string(port_) +
"/ws-subprotocol-unoffered",
headers);
ASSERT_TRUE(client.connect());
EXPECT_TRUE(client.subprotocol().empty());
client.close();
}
TEST_F(WebSocketIntegrationTest, SubProtocolNotRequested) { TEST_F(WebSocketIntegrationTest, SubProtocolNotRequested) {
// Connect without requesting any subprotocol // Connect without requesting any subprotocol
ws::WebSocketClient client("ws://localhost:" + std::to_string(port_) + ws::WebSocketClient client("ws://localhost:" + std::to_string(port_) +