diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 63cfd810..78ca0b22 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -4,6 +4,8 @@ All notable changes to this project will be documented in this file. ## [6.2.0] - 2019-09-09 - websocket and http server: server does not close the bound client socket in many cases +- improve some websocket error messages +- add a utility function with unittest to parse status line and stop using scanf which triggers warnings on Windows ## [6.1.0] - 2019-09-08 diff --git a/ixwebsocket/IXHttp.cpp b/ixwebsocket/IXHttp.cpp index 83b544a1..ceddbbb3 100644 --- a/ixwebsocket/IXHttp.cpp +++ b/ixwebsocket/IXHttp.cpp @@ -27,6 +27,36 @@ namespace ix return out; } + std::pair Http::parseStatusLine(const std::string& line) + { + // Request-Line = Method SP Request-URI SP HTTP-Version CRLF + std::string token; + std::stringstream tokenStream(line); + std::vector tokens; + + // Split by ' ' + while (std::getline(tokenStream, token, ' ')) + { + tokens.push_back(token); + } + + std::string httpVersion; + if (tokens.size() >= 1) + { + httpVersion = trim(tokens[0]); + } + + int statusCode = -1; + if (tokens.size() >= 2) + { + std::stringstream ss; + ss << trim(tokens[1]); + ss >> statusCode; + } + + return std::make_pair(httpVersion, statusCode); + } + std::tuple Http::parseRequestLine(const std::string& line) { // Request-Line = Method SP Request-URI SP HTTP-Version CRLF diff --git a/ixwebsocket/IXHttp.h b/ixwebsocket/IXHttp.h index 81da6edb..e3fd310a 100644 --- a/ixwebsocket/IXHttp.h +++ b/ixwebsocket/IXHttp.h @@ -115,6 +115,8 @@ namespace ix std::shared_ptr socket); static bool sendResponse(HttpResponsePtr response, std::shared_ptr socket); + static std::pair parseStatusLine( + const std::string& line); static std::tuple parseRequestLine( const std::string& line); static std::string trim(const std::string& str); diff --git a/ixwebsocket/IXWebSocketHandshake.cpp b/ixwebsocket/IXWebSocketHandshake.cpp index f699a0dc..2e03423c 100644 --- a/ixwebsocket/IXWebSocketHandshake.cpp +++ b/ixwebsocket/IXWebSocketHandshake.cpp @@ -164,20 +164,23 @@ namespace ix } // Validate status - int status; + auto statusLine = Http::parseStatusLine(line); + std::string httpVersion = statusLine.first; + int status = statusLine.second; // HTTP/1.0 is too old. - if (sscanf(line.c_str(), "HTTP/1.0 %d", &status) == 1) + if (httpVersion != "HTTP/1.1") { std::stringstream ss; - ss << "Server version is HTTP/1.0. Rejecting connection to " << host + ss << "Expecting HTTP/1.1, got " << httpVersion << ". " + << "Rejecting connection to " << host << ", status: " << status << ", HTTP Status line: " << line; return WebSocketInitResult(false, status, ss.str()); } // We want an 101 HTTP status - if (sscanf(line.c_str(), "HTTP/1.1 %d", &status) != 1 || status != 101) + if (status != 101) { std::stringstream ss; ss << "Got bad status connecting to " << host @@ -295,9 +298,15 @@ namespace ix return sendErrorResponse(400, "Missing Sec-WebSocket-Key value"); } + if (headers.find("upgrade") == headers.end()) + { + return sendErrorResponse(400, "Missing Upgrade header"); + } + if (!insensitiveStringCompare(headers["upgrade"], "WebSocket")) { - return sendErrorResponse(400, "Invalid or missing Upgrade header"); + return sendErrorResponse(400, "Invalid Upgrade header, " + "need WebSocket, got " + headers["upgrade"]); } if (headers.find("sec-websocket-version") == headers.end()) @@ -314,7 +323,7 @@ namespace ix if (version != 13) { return sendErrorResponse(400, "Invalid Sec-WebSocket-Version, " - "need 13, got" + ss.str()); + "need 13, got " + ss.str()); } } diff --git a/ixwebsocket/IXWebSocketTransport.cpp b/ixwebsocket/IXWebSocketTransport.cpp index 3fe2e74e..2a5d6707 100644 --- a/ixwebsocket/IXWebSocketTransport.cpp +++ b/ixwebsocket/IXWebSocketTransport.cpp @@ -681,8 +681,12 @@ namespace ix reason = WebSocketCloseConstants::kInvalidFramePayloadDataMessage; } + // // Validate close codes. Autobahn 7.9.* - // 1014, 1015 are debattable. The firefox MSDN has a description for them + // 1014, 1015 are debattable. The firefox MSDN has a description for them. + // Full list of status code and status range is defined in the dedicated + // RFC section at https://tools.ietf.org/html/rfc6455#page-45 + // if (code < 1000 || code == 1004 || code == 1006 || (code > 1013 && code < 3000)) { diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index bdb4fcd3..205b9b4a 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -62,6 +62,7 @@ set (SOURCES IXHttpClientTest.cpp IXHttpServerTest.cpp IXUnityBuildsTest.cpp + IXHttpTest.cpp ) # Some unittest don't work on windows yet