diff --git a/httplib.h b/httplib.h index e2d7b170..d30f0d68 100644 --- a/httplib.h +++ b/httplib.h @@ -8905,7 +8905,8 @@ inline bool is_field_value(const std::string &s) { return is_field_content(s); } } // namespace fields inline bool perform_websocket_handshake(Stream &strm, const std::string &host, - int port, const std::string &path, + int port, bool is_ssl, + const std::string &path, const Headers &headers, std::string &selected_subprotocol) { // Validate path and host @@ -8931,7 +8932,7 @@ inline bool perform_websocket_handshake(Stream &strm, const std::string &host, // Build upgrade request std::string req_str = "GET " + path + " HTTP/1.1\r\n"; - req_str += "Host: " + host + ":" + std::to_string(port) + "\r\n"; + req_str += "Host: " + make_host_and_port_string(host, port, is_ssl) + "\r\n"; req_str += "Upgrade: websocket\r\n"; req_str += "Connection: Upgrade\r\n"; req_str += "Sec-WebSocket-Key: " + client_key + "\r\n"; @@ -20570,9 +20571,15 @@ inline bool WebSocketClient::connect() { return false; } +#ifdef CPPHTTPLIB_SSL_ENABLED + auto is_ssl = is_ssl_; +#else + auto is_ssl = false; +#endif + std::string selected_subprotocol; - if (!detail::perform_websocket_handshake(*strm, host_, port_, path_, headers_, - selected_subprotocol)) { + if (!detail::perform_websocket_handshake(*strm, host_, port_, is_ssl, path_, + headers_, selected_subprotocol)) { shutdown_and_close(); return false; } diff --git a/test/test.cc b/test/test.cc index 85f9cbc8..d3f8e25a 100644 --- a/test/test.cc +++ b/test/test.cc @@ -18975,6 +18975,47 @@ TEST(WebSocketTest, QueryStringInHandshake) { t.join(); } +TEST(WebSocketTest, HostHeaderInHandshake) { + Server svr; + + std::mutex mtx; + std::string received_host; + + svr.WebSocket("/ws", [&](const Request &req, ws::WebSocket &ws) { + { + std::lock_guard lock(mtx); + received_host = req.get_header_value("Host"); + } + 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"); + 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)); + client.close(); + + { + std::lock_guard lock(mtx); + // Non-default port must be present in the Host header. Default ports + // (80/443) are omitted; that logic is covered by + // MakeHostAndPortStringTest. + EXPECT_EQ("localhost:" + std::to_string(port), received_host); + } + + svr.stop(); + t.join(); +} + #ifdef CPPHTTPLIB_OPENSSL_SUPPORT class WebSocketSSLIntegrationTest : public ::testing::Test { protected: