diff --git a/ixwebsocket/IXWebSocketHandshake.cpp b/ixwebsocket/IXWebSocketHandshake.cpp index 986b270c..39476cab 100644 --- a/ixwebsocket/IXWebSocketHandshake.cpp +++ b/ixwebsocket/IXWebSocketHandshake.cpp @@ -63,7 +63,9 @@ namespace ix return s; } - WebSocketInitResult WebSocketHandshake::sendErrorResponse(int code, const std::string& reason) + WebSocketInitResult WebSocketHandshake::sendErrorResponse(int code, + const std::string& reason, + const std::string& extraHeaders) { std::stringstream ss; ss << "HTTP/1.1 "; @@ -72,6 +74,8 @@ namespace ix ss << reason; ss << "\r\n"; ss << "Server: " << userAgent() << "\r\n"; + ss << extraHeaders; + ss << "\r\n"; // Socket write can only be cancelled through a timeout here, not manually. static std::atomic requestInitCancellation(false); @@ -354,10 +358,12 @@ namespace ix if (version != 13) { - return sendErrorResponse(400, + // Tell the client which version is supported (RFC 6455 section 4.2.2) + return sendErrorResponse(426, "Invalid Sec-WebSocket-Version, " "need 13, got " + - ss.str()); + ss.str(), + "Sec-WebSocket-Version: 13\r\n"); } } diff --git a/ixwebsocket/IXWebSocketHandshake.h b/ixwebsocket/IXWebSocketHandshake.h index a6bf2a15..40a33e9f 100644 --- a/ixwebsocket/IXWebSocketHandshake.h +++ b/ixwebsocket/IXWebSocketHandshake.h @@ -45,7 +45,9 @@ namespace ix std::string genRandomString(const int len); // Parse HTTP headers - WebSocketInitResult sendErrorResponse(int code, const std::string& reason); + WebSocketInitResult sendErrorResponse(int code, + const std::string& reason, + const std::string& extraHeaders = std::string()); bool insensitiveStringCompare(const std::string& a, const std::string& b); diff --git a/test/IXWebSocketServerTest.cpp b/test/IXWebSocketServerTest.cpp index 88394900..e02f989c 100644 --- a/test/IXWebSocketServerTest.cpp +++ b/test/IXWebSocketServerTest.cpp @@ -155,6 +155,60 @@ TEST_CASE("Websocket_server", "[websocket_server]") REQUIRE(server.getClients().size() == 0); } + SECTION("Send a request with an unsupported version. Should return 426 with the supported " + "version and end the response headers") + { + int port = getFreePort(); + ix::WebSocketServer server(port); + std::string connectionId; + REQUIRE(startServer(server, connectionId)); + + std::string errMsg; + bool tls = false; + SocketTLSOptions tlsOptions; + std::shared_ptr socket = createSocket(tls, -1, errMsg, tlsOptions); + std::string host("127.0.0.1"); + auto isCancellationRequested = []() -> bool { return false; }; + bool success = socket->connect(host, port, errMsg, isCancellationRequested); + REQUIRE(success); + + socket->writeBytes("GET / HTTP/1.1\r\n" + "Upgrade: websocket\r\n" + "Sec-WebSocket-Version: 8\r\n" + "Sec-WebSocket-Key: foobar\r\n" + "\r\n", + isCancellationRequested); + + auto lineResult = socket->readLine(isCancellationRequested); + REQUIRE(lineResult.first); + + int status = -1; + REQUIRE(sscanf(lineResult.second.c_str(), "HTTP/1.1 %d", &status) == 1); + REQUIRE(status == 426); + + bool supportedVersionSent = false; + bool headersEnded = false; + while (true) + { + lineResult = socket->readLine(isCancellationRequested); + if (!lineResult.first) break; + if (lineResult.second == "\r\n") + { + headersEnded = true; + break; + } + if (lineResult.second == "Sec-WebSocket-Version: 13\r\n") + { + supportedVersionSent = true; + } + } + REQUIRE(supportedVersionSent); + REQUIRE(headersEnded); + + server.stop(); + REQUIRE(server.getClients().size() == 0); + } + SECTION("Connect to the server. Send GET request with correct header") { int port = getFreePort();