Browse Source

Fix WebSocketClient dropping query string from URL during handshake (#2468)

The constructor stored only uc.path in path_, discarding uc.query, so the
WebSocket upgrade handshake sent the Request-URI without the query string.
Append the query to path_ so query parameters (e.g. auth tokens) are sent.
yhirose 2 months ago
parent
commit
79d83feb18
2 changed files with 46 additions and 0 deletions
  1. 1 0
      httplib.h
  2. 45 0
      test/test.cc

+ 1 - 0
httplib.h

@@ -20266,6 +20266,7 @@ inline WebSocketClient::WebSocketClient(
     if (!uc.port.empty() && !detail::parse_port(uc.port, port_)) { return; }
     if (!uc.port.empty() && !detail::parse_port(uc.port, port_)) { return; }
 
 
     path_ = std::move(uc.path);
     path_ = std::move(uc.path);
+    if (!uc.query.empty()) { path_ += uc.query; }
 
 
 #ifdef CPPHTTPLIB_SSL_ENABLED
 #ifdef CPPHTTPLIB_SSL_ENABLED
     is_ssl_ = is_ssl;
     is_ssl_ = is_ssl;

+ 45 - 0
test/test.cc

@@ -18191,6 +18191,51 @@ TEST(WebSocketPreRoutingTest, RejectWithoutAuth) {
   t.join();
   t.join();
 }
 }
 
 
+TEST(WebSocketTest, QueryStringInHandshake) {
+  Server svr;
+
+  std::mutex mtx;
+  std::string received_target;
+  std::string received_token;
+
+  svr.WebSocket("/ws", [&](const Request &req, ws::WebSocket &ws) {
+    {
+      std::lock_guard<std::mutex> lock(mtx);
+      received_target = req.target;
+      if (req.has_param("token")) {
+        received_token = req.get_param_value("token");
+      }
+    }
+    std::string msg;
+    while (ws.read(msg)) {
+      ws.send(msg);
+    }
+  });
+
+  auto port = svr.bind_to_any_port("localhost");
+  std::thread t([&]() { svr.listen_after_bind(); });
+  svr.wait_until_ready();
+
+  ws::WebSocketClient client("ws://localhost:" + std::to_string(port) +
+                             "/ws?token=ABC&session=123");
+  ASSERT_TRUE(client.connect());
+  // Round-trip ensures the handler has run and captured the request.
+  ASSERT_TRUE(client.send("hello"));
+  std::string msg;
+  ASSERT_TRUE(client.read(msg));
+  EXPECT_EQ("hello", msg);
+  client.close();
+
+  {
+    std::lock_guard<std::mutex> lock(mtx);
+    EXPECT_EQ("/ws?token=ABC&session=123", received_target);
+    EXPECT_EQ("ABC", received_token);
+  }
+
+  svr.stop();
+  t.join();
+}
+
 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
 class WebSocketSSLIntegrationTest : public ::testing::Test {
 class WebSocketSSLIntegrationTest : public ::testing::Test {
 protected:
 protected: