From 79d83feb1829dc6e44d636019e2883662c1b89ff Mon Sep 17 00:00:00 2001 From: yhirose Date: Sun, 7 Jun 2026 17:08:11 -0400 Subject: [PATCH] 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. --- httplib.h | 1 + test/test.cc | 45 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/httplib.h b/httplib.h index b36cbc0..4fc027d 100644 --- a/httplib.h +++ b/httplib.h @@ -20266,6 +20266,7 @@ inline WebSocketClient::WebSocketClient( if (!uc.port.empty() && !detail::parse_port(uc.port, port_)) { return; } path_ = std::move(uc.path); + if (!uc.query.empty()) { path_ += uc.query; } #ifdef CPPHTTPLIB_SSL_ENABLED is_ssl_ = is_ssl; diff --git a/test/test.cc b/test/test.cc index 223c6a1..949edfe 100644 --- a/test/test.cc +++ b/test/test.cc @@ -18191,6 +18191,51 @@ TEST(WebSocketPreRoutingTest, RejectWithoutAuth) { 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 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 lock(mtx); + EXPECT_EQ("/ws?token=ABC&session=123", received_target); + EXPECT_EQ("ABC", received_token); + } + + svr.stop(); + t.join(); +} + #ifdef CPPHTTPLIB_OPENSSL_SUPPORT class WebSocketSSLIntegrationTest : public ::testing::Test { protected: