diff --git a/ixwebsocket/IXHttpServer.cpp b/ixwebsocket/IXHttpServer.cpp index a4e686fa..5ed667d4 100644 --- a/ixwebsocket/IXHttpServer.cpp +++ b/ixwebsocket/IXHttpServer.cpp @@ -9,6 +9,7 @@ #include "IXNetSystem.h" #include "IXSocketConnect.h" #include "IXSocketFactory.h" +#include "IXUserAgent.h" #include #include #include @@ -112,6 +113,9 @@ namespace ix uri = "/index.html"; } + WebSocketHttpHeaders headers; + headers["Server"] = userAgent(); + std::string path("." + uri); auto res = readAsString(path); bool found = res.first; @@ -129,7 +133,6 @@ namespace ix << request->uri << " " << content.size(); logInfo(ss.str()); - WebSocketHttpHeaders headers; // FIXME: check extensions to set the content type // headers["Content-Type"] = "application/octet-stream"; headers["Accept-Ranges"] = "none"; @@ -143,4 +146,36 @@ namespace ix 200, "OK", HttpErrorCode::Ok, headers, content); }); } + + void HttpServer::makeRedirectServer(const std::string& redirectUrl) + { + // + // See https://developer.mozilla.org/en-US/docs/Web/HTTP/Redirections + // + setOnConnectionCallback( + [this, redirectUrl]( + HttpRequestPtr request, + std::shared_ptr /*connectionState*/) -> HttpResponsePtr { + + WebSocketHttpHeaders headers; + headers["Server"] = userAgent(); + + // Log request + std::stringstream ss; + ss << request->method << " " << request->headers["User-Agent"] << " " + << request->uri; + logInfo(ss.str()); + + if (request->method == "POST") + { + return std::make_shared( + 200, "OK", HttpErrorCode::Ok, headers, std::string()); + } + + headers["Location"] = redirectUrl; + + return std::make_shared( + 301, "OK", HttpErrorCode::Ok, headers, std::string()); + }); + } } // namespace ix diff --git a/ixwebsocket/IXHttpServer.h b/ixwebsocket/IXHttpServer.h index 67c2c6b1..60da4129 100644 --- a/ixwebsocket/IXHttpServer.h +++ b/ixwebsocket/IXHttpServer.h @@ -34,6 +34,8 @@ namespace ix void setOnConnectionCallback(const OnConnectionCallback& callback); + void makeRedirectServer(const std::string& redirectUrl); + private: // Member variables OnConnectionCallback _onConnectionCallback; diff --git a/ixwebsocket/IXWebSocketHandshake.cpp b/ixwebsocket/IXWebSocketHandshake.cpp index 87f94df0..9459028e 100644 --- a/ixwebsocket/IXWebSocketHandshake.cpp +++ b/ixwebsocket/IXWebSocketHandshake.cpp @@ -69,6 +69,7 @@ namespace ix ss << " "; ss << reason; ss << "\r\n"; + ss << "Server: " << userAgent() << "\r\n"; // Socket write can only be cancelled through a timeout here, not manually. static std::atomic requestInitCancellation(false); diff --git a/test/IXHttpServerTest.cpp b/test/IXHttpServerTest.cpp index 303035b8..53d4eef5 100644 --- a/test/IXHttpServerTest.cpp +++ b/test/IXHttpServerTest.cpp @@ -62,4 +62,55 @@ TEST_CASE("http server", "[httpd]") server.stop(); } + + SECTION("Connect to a local HTTP server, with redirection enabled") + { + int port = getFreePort(); + ix::HttpServer server(port, "127.0.0.1"); + server.makeRedirectServer("http://example.com"); + + auto res = server.listen(); + REQUIRE(res.first); + server.start(); + + HttpClient httpClient; + WebSocketHttpHeaders headers; + + std::string url("http://127.0.0.1:"); + url += std::to_string(port); + url += "/data/foo.txt"; + auto args = httpClient.createRequest(url); + + args->extraHeaders = headers; + args->connectTimeout = 60; + args->transferTimeout = 60; + args->followRedirects = false; // we dont want to follow redirect during testing + args->maxRedirects = 10; + args->verbose = true; + args->compress = true; + args->logger = [](const std::string& msg) { std::cout << msg; }; + args->onProgressCallback = [](int current, int total) -> bool { + std::cerr << "\r" + << "Downloaded " << current << " bytes out of " << total; + return true; + }; + + auto response = httpClient.get(url, args); + + for (auto it : response->headers) + { + std::cerr << it.first << ": " << it.second << std::endl; + } + + std::cerr << "Upload size: " << response->uploadSize << std::endl; + std::cerr << "Download size: " << response->downloadSize << std::endl; + std::cerr << "Status: " << response->statusCode << std::endl; + std::cerr << "Error message: " << response->errorMsg << std::endl; + + REQUIRE(response->errorCode == HttpErrorCode::Ok); + REQUIRE(response->statusCode == 301); + REQUIRE(response->headers["Location"] == "http://example.com"); + + server.stop(); + } } diff --git a/ws/ws_httpd.cpp b/ws/ws_httpd.cpp index 52714116..16729a55 100644 --- a/ws/ws_httpd.cpp +++ b/ws/ws_httpd.cpp @@ -24,33 +24,7 @@ namespace ix if (redirect) { - // - // See https://developer.mozilla.org/en-US/docs/Web/HTTP/Redirections - // - server.setOnConnectionCallback( - [redirectUrl]( - HttpRequestPtr request, - std::shared_ptr /*connectionState*/) -> HttpResponsePtr { - - WebSocketHttpHeaders headers; - - // Log request - std::stringstream ss; - ss << request->method << " " << request->headers["User-Agent"] << " " - << request->uri; - spdlog::info(ss.str()); - - if (request->method == "POST") - { - return std::make_shared( - 200, "OK", HttpErrorCode::Ok, headers, std::string()); - } - - headers["Location"] = redirectUrl; - - return std::make_shared( - 301, "OK", HttpErrorCode::Ok, headers, std::string()); - }); + server.makeRedirectServer(redirectUrl); } auto res = server.listen();