aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDan Engelbrecht <[email protected]>2026-02-12 10:58:41 +0100
committerGitHub Enterprise <[email protected]>2026-02-12 10:58:41 +0100
commitc37421a3b4493c0b0f9afef15a4ea7b74d152067 (patch)
treeb1d95430ed3518490304a6a128aee4e2aeed84d3 /src
parentreduce lock time for project store gc precache and gc validate (#750) (diff)
downloadzen-c37421a3b4493c0b0f9afef15a4ea7b74d152067.tar.xz
zen-c37421a3b4493c0b0f9afef15a4ea7b74d152067.zip
add simple http client tests (#751)
* add simple http client tests and fix run loop of http server to not rely on application quit
Diffstat (limited to 'src')
-rw-r--r--src/zenhttp/httpclient.cpp164
-rw-r--r--src/zenhttp/include/zenhttp/httpserver.h4
-rw-r--r--src/zenhttp/servers/httpasio.cpp17
-rw-r--r--src/zenhttp/servers/httpasio.h2
-rw-r--r--src/zenhttp/servers/httpmulti.cpp11
-rw-r--r--src/zenhttp/servers/httpnull.cpp11
-rw-r--r--src/zenhttp/servers/httpsys.cpp18
-rw-r--r--src/zenhttp/transports/winsocktransport.cpp2
8 files changed, 202 insertions, 27 deletions
diff --git a/src/zenhttp/httpclient.cpp b/src/zenhttp/httpclient.cpp
index 43e9fb468..0544bf5c8 100644
--- a/src/zenhttp/httpclient.cpp
+++ b/src/zenhttp/httpclient.cpp
@@ -22,8 +22,13 @@
#include "clients/httpclientcommon.h"
#if ZEN_WITH_TESTS
+# include <zencore/scopeguard.h>
# include <zencore/testing.h>
# include <zencore/testutils.h>
+# include "servers/httpasio.h"
+# include "servers/httpsys.h"
+
+# include <thread>
#endif // ZEN_WITH_TESTS
namespace zen {
@@ -388,7 +393,164 @@ TEST_CASE("httpclient")
{
using namespace std::literals;
- SUBCASE("client") {}
+ struct TestHttpService : public HttpService
+ {
+ TestHttpService() = default;
+
+ virtual const char* BaseUri() const override { return "/test/"; }
+ virtual void HandleRequest(HttpServerRequest& HttpServiceRequest) override
+ {
+ if (HttpServiceRequest.RelativeUri() == "yo")
+ {
+ return HttpServiceRequest.WriteResponse(HttpResponseCode::OK, HttpContentType::kText, "hey man");
+ }
+ return HttpServiceRequest.WriteResponse(HttpResponseCode::OK);
+ }
+ };
+
+ TestHttpService TestService;
+ ScopedTemporaryDirectory TmpDir;
+
+ SUBCASE("asio")
+ {
+ Ref<HttpServer> AsioServer = CreateHttpAsioServer(AsioConfig{});
+
+ int Port = AsioServer->Initialize(7575, TmpDir.Path());
+ REQUIRE(Port != -1);
+
+ AsioServer->RegisterService(TestService);
+
+ std::thread SeverThread([&]() { AsioServer->Run(false); });
+
+ {
+ auto _ = MakeGuard([&]() {
+ if (SeverThread.joinable())
+ {
+ SeverThread.join();
+ }
+ AsioServer->Close();
+ });
+
+ {
+ HttpClient Client(fmt::format("127.0.0.1:{}", Port),
+ HttpClientSettings{},
+ /*CheckIfAbortFunction*/ {});
+
+ ZEN_INFO("Request using {}", Client.GetBaseUri());
+
+ HttpClient::Response TestResponse = Client.Get("/test/yo");
+ CHECK(TestResponse.IsSuccess());
+ }
+
+ if (IsIPv6Capable())
+ {
+ HttpClient Client(fmt::format("[::1]:{}", Port),
+ HttpClientSettings{},
+ /*CheckIfAbortFunction*/ {});
+
+ ZEN_INFO("Request using {}", Client.GetBaseUri());
+
+ HttpClient::Response TestResponse = Client.Get("/test/yo");
+ CHECK(TestResponse.IsSuccess());
+ }
+
+ {
+ HttpClient Client(fmt::format("localhost:{}", Port),
+ HttpClientSettings{},
+ /*CheckIfAbortFunction*/ {});
+
+ ZEN_INFO("Request using {}", Client.GetBaseUri());
+
+ HttpClient::Response TestResponse = Client.Get("/test/yo");
+ CHECK(TestResponse.IsSuccess());
+ }
+# if 0
+ {
+ HttpClient Client(fmt::format("10.24.101.77:{}", Port),
+ HttpClientSettings{},
+ /*CheckIfAbortFunction*/ {});
+
+ ZEN_INFO("Request using {}", Client.GetBaseUri());
+
+ HttpClient::Response TestResponse = Client.Get("/test/yo");
+ CHECK(TestResponse.IsSuccess());
+ }
+# endif // 0
+ AsioServer->RequestExit();
+ }
+ }
+
+# if ZEN_PLATFORM_WINDOWS
+ SUBCASE("httpsys")
+ {
+ Ref<HttpServer> HttpSysServer = CreateHttpSysServer(HttpSysConfig{.ForceLoopback = true});
+
+ int Port = HttpSysServer->Initialize(7575, TmpDir.Path());
+ REQUIRE(Port != -1);
+
+ HttpSysServer->RegisterService(TestService);
+
+ std::thread SeverThread([&]() { HttpSysServer->Run(false); });
+
+ {
+ auto _ = MakeGuard([&]() {
+ if (SeverThread.joinable())
+ {
+ SeverThread.join();
+ }
+ HttpSysServer->Close();
+ });
+
+ if (true)
+ {
+ HttpClient Client(fmt::format("127.0.0.1:{}", Port),
+ HttpClientSettings{},
+ /*CheckIfAbortFunction*/ {});
+
+ ZEN_INFO("Request using {}", Client.GetBaseUri());
+
+ HttpClient::Response TestResponse = Client.Get("/test/yo");
+ CHECK(TestResponse.IsSuccess());
+ }
+
+ if (IsIPv6Capable())
+ {
+ HttpClient Client(fmt::format("[::1]:{}", Port),
+ HttpClientSettings{},
+ /*CheckIfAbortFunction*/ {});
+
+ ZEN_INFO("Request using {}", Client.GetBaseUri());
+
+ HttpClient::Response TestResponse = Client.Get("/test/yo");
+ CHECK(TestResponse.IsSuccess());
+ }
+
+ {
+ HttpClient Client(fmt::format("localhost:{}", Port),
+ HttpClientSettings{},
+ /*CheckIfAbortFunction*/ {});
+
+ ZEN_INFO("Request using {}", Client.GetBaseUri());
+
+ HttpClient::Response TestResponse = Client.Get("/test/yo");
+ CHECK(TestResponse.IsSuccess());
+ }
+# if 0
+ {
+ HttpClient Client(fmt::format("10.24.101.77:{}", Port),
+ HttpClientSettings{},
+ /*CheckIfAbortFunction*/ {});
+
+ ZEN_INFO("Request using {}", Client.GetBaseUri());
+
+ HttpClient::Response TestResponse = Client.Get("/test");
+ CHECK(TestResponse.IsSuccess());
+ }
+# endif // 0
+ HttpSysServer->RequestExit();
+ }
+ }
+# endif // ZEN_PLATFORM_WINDOWS
}
void
diff --git a/src/zenhttp/include/zenhttp/httpserver.h b/src/zenhttp/include/zenhttp/httpserver.h
index 3438a1471..6660bebf9 100644
--- a/src/zenhttp/include/zenhttp/httpserver.h
+++ b/src/zenhttp/include/zenhttp/httpserver.h
@@ -30,8 +30,10 @@ class HttpService;
*/
class HttpServerRequest
{
-public:
+protected:
explicit HttpServerRequest(HttpService& Service);
+
+public:
~HttpServerRequest();
// Synchronous operations
diff --git a/src/zenhttp/servers/httpasio.cpp b/src/zenhttp/servers/httpasio.cpp
index 18a0f6a40..76fea65b3 100644
--- a/src/zenhttp/servers/httpasio.cpp
+++ b/src/zenhttp/servers/httpasio.cpp
@@ -97,7 +97,11 @@ IsIPv6AvailableSysctl(void)
return val == 0;
}
+#endif // ZEN_PLATFORM_LINUX
+namespace zen {
+
+#if ZEN_PLATFORM_LINUX
bool
IsIPv6Capable()
{
@@ -121,8 +125,6 @@ IsIPv6Capable()
}
#endif
-namespace zen {
-
const FLLMTag&
GetHttpasioTag()
{
@@ -1992,7 +1994,8 @@ HttpAsioServer::OnInitialize(int BasePort, std::filesystem::path DataDir)
void
HttpAsioServer::OnRun(bool IsInteractive)
{
- const int WaitTimeout = 1000;
+ const int WaitTimeout = 1000;
+ bool ShutdownRequested = false;
#if ZEN_PLATFORM_WINDOWS
if (IsInteractive)
@@ -2012,8 +2015,8 @@ HttpAsioServer::OnRun(bool IsInteractive)
}
}
- m_ShutdownEvent.Wait(WaitTimeout);
- } while (!IsApplicationExitRequested());
+ ShutdownRequested = m_ShutdownEvent.Wait(WaitTimeout);
+ } while (!ShutdownRequested);
#else
if (IsInteractive)
{
@@ -2022,8 +2025,8 @@ HttpAsioServer::OnRun(bool IsInteractive)
do
{
- m_ShutdownEvent.Wait(WaitTimeout);
- } while (!IsApplicationExitRequested());
+ ShutdownRequested = m_ShutdownEvent.Wait(WaitTimeout);
+ } while (!ShutdownRequested);
#endif
}
diff --git a/src/zenhttp/servers/httpasio.h b/src/zenhttp/servers/httpasio.h
index c483dfc28..3ec1141a7 100644
--- a/src/zenhttp/servers/httpasio.h
+++ b/src/zenhttp/servers/httpasio.h
@@ -15,4 +15,6 @@ struct AsioConfig
Ref<HttpServer> CreateHttpAsioServer(const AsioConfig& Config);
+bool IsIPv6Capable();
+
} // namespace zen
diff --git a/src/zenhttp/servers/httpmulti.cpp b/src/zenhttp/servers/httpmulti.cpp
index 31cb04be5..95624245f 100644
--- a/src/zenhttp/servers/httpmulti.cpp
+++ b/src/zenhttp/servers/httpmulti.cpp
@@ -56,7 +56,8 @@ HttpMultiServer::OnInitialize(int BasePort, std::filesystem::path DataDir)
void
HttpMultiServer::OnRun(bool IsInteractiveSession)
{
- const int WaitTimeout = 1000;
+ const int WaitTimeout = 1000;
+ bool ShutdownRequested = false;
#if ZEN_PLATFORM_WINDOWS
if (IsInteractiveSession)
@@ -76,8 +77,8 @@ HttpMultiServer::OnRun(bool IsInteractiveSession)
}
}
- m_ShutdownEvent.Wait(WaitTimeout);
- } while (!IsApplicationExitRequested());
+ ShutdownRequested = m_ShutdownEvent.Wait(WaitTimeout);
+ } while (!ShutdownRequested);
#else
if (IsInteractiveSession)
{
@@ -86,8 +87,8 @@ HttpMultiServer::OnRun(bool IsInteractiveSession)
do
{
- m_ShutdownEvent.Wait(WaitTimeout);
- } while (!IsApplicationExitRequested());
+ ShutdownRequested = m_ShutdownEvent.Wait(WaitTimeout);
+ } while (!ShutdownRequested);
#endif
}
diff --git a/src/zenhttp/servers/httpnull.cpp b/src/zenhttp/servers/httpnull.cpp
index 0ec1cb3c4..b770b97db 100644
--- a/src/zenhttp/servers/httpnull.cpp
+++ b/src/zenhttp/servers/httpnull.cpp
@@ -34,7 +34,8 @@ HttpNullServer::OnInitialize(int BasePort, std::filesystem::path DataDir)
void
HttpNullServer::OnRun(bool IsInteractiveSession)
{
- const int WaitTimeout = 1000;
+ const int WaitTimeout = 1000;
+ bool ShutdownRequested = false;
#if ZEN_PLATFORM_WINDOWS
if (IsInteractiveSession)
@@ -54,8 +55,8 @@ HttpNullServer::OnRun(bool IsInteractiveSession)
}
}
- m_ShutdownEvent.Wait(WaitTimeout);
- } while (!IsApplicationExitRequested());
+ ShutdownRequested = m_ShutdownEvent.Wait(WaitTimeout);
+ } while (!ShutdownRequested);
#else
if (IsInteractiveSession)
{
@@ -64,8 +65,8 @@ HttpNullServer::OnRun(bool IsInteractiveSession)
do
{
- m_ShutdownEvent.Wait(WaitTimeout);
- } while (!IsApplicationExitRequested());
+ ShutdownRequested = m_ShutdownEvent.Wait(WaitTimeout);
+ } while (!ShutdownRequested);
#endif
}
diff --git a/src/zenhttp/servers/httpsys.cpp b/src/zenhttp/servers/httpsys.cpp
index 54cc0c22d..0d2bb8fbd 100644
--- a/src/zenhttp/servers/httpsys.cpp
+++ b/src/zenhttp/servers/httpsys.cpp
@@ -1128,11 +1128,14 @@ HttpSysServer::InitializeServer(int BasePort)
// port for the current user. eg:
// netsh http add urlacl url=http://*:8558/ user=<some_user>
- ZEN_WARN(
- "Unable to register handler using '{}' - falling back to local-only. "
- "Please ensure the appropriate netsh URL reservation configuration "
- "is made to allow http.sys access (see https://github.com/EpicGames/zen/blob/main/README.md)",
- WideToUtf8(WildcardUrlPath));
+ if (!m_InitialConfig.ForceLoopback)
+ {
+ ZEN_WARN(
+ "Unable to register handler using '{}' - falling back to local-only. "
+ "Please ensure the appropriate netsh URL reservation configuration "
+ "is made to allow http.sys access (see https://github.com/EpicGames/zen/blob/main/README.md)",
+ WideToUtf8(WildcardUrlPath));
+ }
const std::u8string_view Hosts[] = {u8"[::1]"sv, u8"localhost"sv, u8"127.0.0.1"sv};
@@ -1337,6 +1340,7 @@ HttpSysServer::OnRun(bool IsInteractive)
ZEN_CONSOLE("Zen Server running (http.sys). Press ESC or Q to quit");
}
+ bool ShutdownRequested = false;
do
{
// int WaitTimeout = -1;
@@ -1357,9 +1361,9 @@ HttpSysServer::OnRun(bool IsInteractive)
}
}
- m_ShutdownEvent.Wait(WaitTimeout);
+ ShutdownRequested = m_ShutdownEvent.Wait(WaitTimeout);
UpdateLofreqTimerValue();
- } while (!IsApplicationExitRequested());
+ } while (!ShutdownRequested);
}
void
diff --git a/src/zenhttp/transports/winsocktransport.cpp b/src/zenhttp/transports/winsocktransport.cpp
index c06a50c95..0217ed44e 100644
--- a/src/zenhttp/transports/winsocktransport.cpp
+++ b/src/zenhttp/transports/winsocktransport.cpp
@@ -322,7 +322,7 @@ SocketTransportPluginImpl::Initialize(TransportServer* ServerInterface)
else
{
}
- } while (!IsApplicationExitRequested() && m_KeepRunning.test());
+ } while (m_KeepRunning.test());
ZEN_INFO("HTTP plugin server accept thread exit");
});