Переглянути джерело

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.
yhirose 3 днів тому
батько
коміт
6d1049462d
3 змінених файлів з 31 додано та 1 видалено
  1. 1 1
      README-websocket.md
  2. 6 0
      httplib.h
  3. 24 0
      test/test.cc

+ 1 - 1
README-websocket.md

@@ -119,7 +119,7 @@ using SubProtocolSelector =
     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)
 

+ 6 - 0
httplib.h

@@ -14692,6 +14692,12 @@ Server::process_request(Stream &strm, const std::string &remote_addr,
                             protocols.emplace_back(b, e);
                           });
             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 - 0
test/test.cc

@@ -24061,6 +24061,18 @@ protected:
           }
           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() {
@@ -24403,6 +24415,18 @@ TEST_F(WebSocketIntegrationTest, SubProtocolNoMatch) {
   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) {
   // Connect without requesting any subprotocol
   ws::WebSocketClient client("ws://localhost:" + std::to_string(port_) +