From ed2ed0f7ae0604de83c3a08ef72471cfec6445bd Mon Sep 17 00:00:00 2001 From: Benjamin Sergeant Date: Fri, 14 Aug 2020 18:13:34 -0700 Subject: [PATCH] (ixwebsocket client) handle HTTP redirects --- docs/CHANGELOG.md | 4 ++ ixwebsocket/IXWebSocketHandshake.cpp | 22 ++++---- ixwebsocket/IXWebSocketTransport.cpp | 78 ++++++++++++++++++---------- ixwebsocket/IXWebSocketVersion.h | 2 +- 4 files changed, 69 insertions(+), 37 deletions(-) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 279d0d8e..92ec03e6 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -2,6 +2,10 @@ All changes to this project will be documented in this file. +## [10.2.0] - 2020-08-14 + +(ixwebsocket client) handle HTTP redirects + ## [10.2.0] - 2020-08-13 (ws) upgrade to latest version of nlohmann json (3.9.1 from 3.2.0) diff --git a/ixwebsocket/IXWebSocketHandshake.cpp b/ixwebsocket/IXWebSocketHandshake.cpp index 2c972c80..4ff676d8 100644 --- a/ixwebsocket/IXWebSocketHandshake.cpp +++ b/ixwebsocket/IXWebSocketHandshake.cpp @@ -170,20 +170,11 @@ namespace ix { std::stringstream ss; ss << "Expecting HTTP/1.1, got " << httpVersion << ". " - << "Rejecting connection to " << host << ":" << port << ", status: " << status + << "Rejecting connection to " << url << ", status: " << status << ", HTTP Status line: " << line; return WebSocketInitResult(false, status, ss.str()); } - // We want an 101 HTTP status - if (status != 101) - { - std::stringstream ss; - ss << "Expecting status 101 (Switching Protocol), got " << status - << " status connecting to " << host << ":" << port << ", HTTP Status line: " << line; - return WebSocketInitResult(false, status, ss.str()); - } - auto result = parseHttpHeaders(_socket, isCancellationRequested); auto headersValid = result.first; auto headers = result.second; @@ -193,6 +184,17 @@ namespace ix return WebSocketInitResult(false, status, "Error parsing HTTP headers"); } + // We want an 101 HTTP status for websocket, otherwise it could be + // a redirection (like 301) + if (status != 101) + { + std::stringstream ss; + ss << "Expecting status 101 (Switching Protocol), got " << status + << " status connecting to " << url << ", HTTP Status line: " << line; + + return WebSocketInitResult(false, status, ss.str(), headers, path); + } + // Check the presence of the connection field if (headers.find("connection") == headers.end()) { diff --git a/ixwebsocket/IXWebSocketTransport.cpp b/ixwebsocket/IXWebSocketTransport.cpp index 730249fd..43e9c53b 100644 --- a/ixwebsocket/IXWebSocketTransport.cpp +++ b/ixwebsocket/IXWebSocketTransport.cpp @@ -107,36 +107,62 @@ namespace ix std::string protocol, host, path, query; int port; + std::string remoteUrl(url); - if (!UrlParser::parse(url, protocol, host, path, query, port)) + WebSocketInitResult result; + const int maxRedirections = 10; + + for (int i = 0; i < maxRedirections; ++i) { - std::stringstream ss; - ss << "Could not parse url: '" << url << "'"; - return WebSocketInitResult(false, 0, ss.str()); + if (!UrlParser::parse(remoteUrl, protocol, host, path, query, port)) + { + std::stringstream ss; + ss << "Could not parse url: '" << url << "'"; + return WebSocketInitResult(false, 0, ss.str()); + } + + std::string errorMsg; + bool tls = protocol == "wss"; + _socket = createSocket(tls, -1, errorMsg, _socketTLSOptions); + _perMessageDeflate = std::make_unique(); + + if (!_socket) + { + return WebSocketInitResult(false, 0, errorMsg); + } + + WebSocketHandshake webSocketHandshake(_requestInitCancellation, + _socket, + _perMessageDeflate, + _perMessageDeflateOptions, + _enablePerMessageDeflate); + + result = webSocketHandshake.clientHandshake( + remoteUrl, headers, host, path, port, timeoutSecs); + + if (result.http_status >= 300 && result.http_status < 400) + { + auto it = result.headers.find("Location"); + if (it == result.headers.end()) + { + std::stringstream ss; + ss << "Missing Location Header for HTTP Redirect response. " + << "Rejecting connection to " << url << ", status: " << result.http_status; + result.errorStr = ss.str(); + break; + } + + remoteUrl = it->second; + continue; + } + + if (result.success) + { + setReadyState(ReadyState::OPEN); + } + return result; } - std::string errorMsg; - bool tls = protocol == "wss"; - _socket = createSocket(tls, -1, errorMsg, _socketTLSOptions); - _perMessageDeflate = std::make_unique(); - - if (!_socket) - { - return WebSocketInitResult(false, 0, errorMsg); - } - - WebSocketHandshake webSocketHandshake(_requestInitCancellation, - _socket, - _perMessageDeflate, - _perMessageDeflateOptions, - _enablePerMessageDeflate); - - auto result = - webSocketHandshake.clientHandshake(url, headers, host, path, port, timeoutSecs); - if (result.success) - { - setReadyState(ReadyState::OPEN); - } return result; } diff --git a/ixwebsocket/IXWebSocketVersion.h b/ixwebsocket/IXWebSocketVersion.h index c4224a6c..8ffbff54 100644 --- a/ixwebsocket/IXWebSocketVersion.h +++ b/ixwebsocket/IXWebSocketVersion.h @@ -6,4 +6,4 @@ #pragma once -#define IX_WEBSOCKET_VERSION "10.2.0" +#define IX_WEBSOCKET_VERSION "10.2.1"