diff options
| author | Stefan Boberg <[email protected]> | 2025-09-29 10:36:32 +0200 |
|---|---|---|
| committer | GitHub Enterprise <[email protected]> | 2025-09-29 10:36:32 +0200 |
| commit | 2f0efec7ab0430f4f4858db87b7eecfbccc0f47c (patch) | |
| tree | 80ce35992a220260cf070fac739626f555de738a | |
| parent | fixed race condition in zen::logging::Get (#519) (diff) | |
| download | zen-2f0efec7ab0430f4f4858db87b7eecfbccc0f47c.tar.xz zen-2f0efec7ab0430f4f4858db87b7eecfbccc0f47c.zip | |
make cpr a HttpClient implementation detail (#517)
these changes remove cpr from anything which is not `HttpClient` internals.
The goal is to eventually replace cpr with a more direct curl interface to eliminate cpr since it's proven problematic due to their development practices which frequently breaks APIs and prevents us from updating vcpkg. But this PR is limited to refactoring existing cpr code to use `HttpClient` instead.
| -rw-r--r-- | src/zen/cmds/rpcreplay_cmd.cpp | 72 | ||||
| -rw-r--r-- | src/zen/zen.cpp | 90 | ||||
| -rw-r--r-- | src/zencore/include/zencore/string.h | 3 | ||||
| -rw-r--r-- | src/zencore/string.cpp | 55 | ||||
| -rw-r--r-- | src/zenhttp/auth/oidc.cpp | 40 | ||||
| -rw-r--r-- | src/zenhttp/httpclient.cpp | 70 | ||||
| -rw-r--r-- | src/zenhttp/httpclientauth.cpp | 18 | ||||
| -rw-r--r-- | src/zenhttp/include/zenhttp/cprutils.h | 86 | ||||
| -rw-r--r-- | src/zenhttp/include/zenhttp/formatters.h | 71 | ||||
| -rw-r--r-- | src/zenhttp/include/zenhttp/httpclient.h | 28 | ||||
| -rw-r--r-- | src/zenserver-test/projectclient.cpp | 160 | ||||
| -rw-r--r-- | src/zenserver-test/projectclient.h | 32 | ||||
| -rw-r--r-- | src/zenserver-test/zenserver-test.cpp | 944 | ||||
| -rw-r--r-- | src/zenserver/cache/httpstructuredcache.cpp | 14 | ||||
| -rw-r--r-- | src/zenserver/projectstore/buildsremoteprojectstore.cpp | 14 | ||||
| -rw-r--r-- | src/zenserver/projectstore/projectstore.cpp | 5 | ||||
| -rw-r--r-- | src/zenserver/upstream/zen.cpp | 226 | ||||
| -rw-r--r-- | src/zenserver/upstream/zen.h | 18 | ||||
| -rw-r--r-- | src/zenutil/zenserverprocess.cpp | 2 |
19 files changed, 854 insertions, 1094 deletions
diff --git a/src/zen/cmds/rpcreplay_cmd.cpp b/src/zen/cmds/rpcreplay_cmd.cpp index fd6c80e98..0cf5e5b6d 100644 --- a/src/zen/cmds/rpcreplay_cmd.cpp +++ b/src/zen/cmds/rpcreplay_cmd.cpp @@ -12,13 +12,13 @@ #include <zencore/stream.h> #include <zencore/timer.h> #include <zencore/workthreadpool.h> +#include <zenhttp/formatters.h> #include <zenhttp/httpclient.h> #include <zenhttp/httpcommon.h> #include <zenhttp/packageformat.h> #include <zenutil/cache/rpcrecording.h> ZEN_THIRD_PARTY_INCLUDES_START -#include <cpr/cpr.h> #include <fmt/format.h> #include <gsl/gsl-lite.hpp> ZEN_THIRD_PARTY_INCLUDES_END @@ -27,54 +27,6 @@ ZEN_THIRD_PARTY_INCLUDES_END namespace zen { -namespace { - // TODO: Convert direct use of cpr to HttpClient - - std::string FormatHttpResponse(const cpr::Response& Response) - { - if (Response.error.code != cpr::ErrorCode::OK) - { - if (Response.error.message.empty()) - { - return fmt::format("Request '{}' failed, error code {}", Response.url.str(), static_cast<int>(Response.error.code)); - } - return fmt::format("Request '{}' failed. Reason: '{}' ({})", - Response.url.str(), - Response.error.message, - static_cast<int>(Response.error.code)); - } - - std::string Content; - if (auto It = Response.header.find("Content-Type"); It != Response.header.end()) - { - zen::HttpContentType ContentType = zen::ParseContentType(It->second); - if (ContentType == zen::HttpContentType::kText) - { - Content = Response.text; - } - else if (ContentType == zen::HttpContentType::kJSON) - { - Content = fmt::format("\n{}", Response.text); - } - else if (!Response.text.empty()) - { - Content = fmt::format("[{}]", MapContentTypeToString(ContentType)); - } - } - - std::string_view ResponseString = zen::ReasonStringForHttpResultCode( - Response.status_code == static_cast<long>(zen::HttpResponseCode::NoContent) ? static_cast<long>(zen::HttpResponseCode::OK) - : Response.status_code); - if (Content.empty()) - { - return std::string(ResponseString); - } - - return fmt::format("{}: {}", ResponseString, Content); - } - -} // namespace - using namespace std::literals; RpcStartRecordingCommand::RpcStartRecordingCommand() @@ -341,8 +293,7 @@ RpcReplayCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv) } }); - cpr::Session Session; - Session.SetUrl(fmt::format("{}/z$/$rpc"sv, m_HostName)); + HttpClient Http{m_HostName}; uint64_t EntryIndex = EntryOffset.fetch_add(m_Stride); while (EntryIndex < EntryCount) @@ -473,9 +424,10 @@ RpcReplayCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv) GetSessionId().ToString(SessionIdString); } - Session.SetHeader({{"Content-Type", std::string(MapContentTypeToString(RequestInfo.ContentType))}, - {"Accept", std::string(MapContentTypeToString(RequestInfo.AcceptType))}, - {"UE-Session", std::string(SessionIdString)}}); + HttpClient::KeyValueMap HttpHeaders{ + {"Content-Type", std::string(MapContentTypeToString(RequestInfo.ContentType))}, + {"Accept", std::string(MapContentTypeToString(RequestInfo.AcceptType))}, + {"UE-Session", std::string(SessionIdString)}}; uint64_t Offset = 0; auto ReadCallback = [&Payload, &Offset](char* buffer, size_t& size, intptr_t) { @@ -486,16 +438,16 @@ RpcReplayCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv) Offset += size; return true; }; - Session.SetReadCallback(cpr::ReadCallback(gsl::narrow<cpr::cpr_off_t>(Payload.GetSize()), ReadCallback)); - cpr::Response Response = Session.Post(); + + HttpClient::Response Response = Http.Post("/z$/$rpc", Payload, HttpHeaders); + BytesSent.fetch_add(Payload.GetSize()); - if (Response.error || !(IsHttpSuccessCode(Response.status_code) || - Response.status_code == gsl::narrow<long>(HttpResponseCode::NotFound))) + if (!Response) { - ZEN_CONSOLE_ERROR("{}", FormatHttpResponse(Response)); + ZEN_CONSOLE_ERROR("{}", Response); break; } - BytesReceived.fetch_add(Response.downloaded_bytes); + BytesReceived.fetch_add(Response.DownloadedBytes); } } diff --git a/src/zen/zen.cpp b/src/zen/zen.cpp index 0381dd15c..1d2faba7e 100644 --- a/src/zen/zen.cpp +++ b/src/zen/zen.cpp @@ -55,7 +55,6 @@ #endif ZEN_THIRD_PARTY_INCLUDES_START -#include <cpr/cpr.h> #include <spdlog/sinks/ansicolor_sink.h> #include <spdlog/spdlog.h> #include <gsl/gsl-lite.hpp> @@ -275,66 +274,37 @@ ZenCmdBase::GetSubCommand(cxxopts::Options&, } static ReturnCode -GetReturnCodeFromHttpResult(int Error, HttpResponseCode ResponseCode) +GetReturnCodeFromHttpResult(const HttpClientError& Ex) { - if ((cpr::ErrorCode)Error != cpr::ErrorCode::OK) - { - switch ((cpr::ErrorCode)Error) - { - case cpr::ErrorCode::CONNECTION_FAILURE: - return ReturnCode::kHttpCantConnectError; - case cpr::ErrorCode::HOST_RESOLUTION_FAILURE: - case cpr::ErrorCode::PROXY_RESOLUTION_FAILURE: - return ReturnCode::kHttpNoHost; - case cpr::ErrorCode::INTERNAL_ERROR: - case cpr::ErrorCode::NETWORK_RECEIVE_ERROR: - case cpr::ErrorCode::NETWORK_SEND_FAILURE: - case cpr::ErrorCode::OPERATION_TIMEDOUT: - return ReturnCode::kHttpTimeout; - case cpr::ErrorCode::SSL_CONNECT_ERROR: - case cpr::ErrorCode::SSL_LOCAL_CERTIFICATE_ERROR: - case cpr::ErrorCode::SSL_REMOTE_CERTIFICATE_ERROR: - case cpr::ErrorCode::SSL_CACERT_ERROR: - case cpr::ErrorCode::GENERIC_SSL_ERROR: - return ReturnCode::kHttpSLLError; - default: - return ReturnCode::kHttpOtherClientError; - } - } - else if (IsHttpSuccessCode(ResponseCode)) - { + HttpClientError::ResponseClass ResponseClass = Ex.GetResponseClass(); + + if (ResponseClass == HttpClientError::ResponseClass::kSuccess) return ReturnCode::kSuccess; - } - else + + switch (ResponseClass) { - switch (ResponseCode) - { - case HttpResponseCode::Unauthorized: - return ReturnCode::kHttpUnauthorized; - case HttpResponseCode::NotFound: - return ReturnCode::kHttpNotFound; - case HttpResponseCode::Forbidden: - return ReturnCode::kHttpForbidden; - case HttpResponseCode::Conflict: - return ReturnCode::kHttpConflict; - case HttpResponseCode::InternalServerError: - return ReturnCode::kHttpInternalServerError; - case HttpResponseCode::ServiceUnavailable: - return ReturnCode::kHttpServiceUnavailable; - case HttpResponseCode::BadGateway: - return ReturnCode::kHttpBadGateway; - case HttpResponseCode::GatewayTimeout: - return ReturnCode::kHttpGatewayTimeout; - default: - if (ResponseCode >= HttpResponseCode::InternalServerError) - { - return ReturnCode::kHttpOtherServerError; - } - else - { - return ReturnCode::kHttpOtherClientError; - } - } +#define HANDLE_CASE(ErrorClass) \ + case HttpClientError::ResponseClass::ErrorClass: \ + return ReturnCode::ErrorClass + + HANDLE_CASE(kHttpOtherClientError); + HANDLE_CASE(kHttpCantConnectError); + HANDLE_CASE(kHttpNotFound); + HANDLE_CASE(kHttpUnauthorized); + HANDLE_CASE(kHttpSLLError); + HANDLE_CASE(kHttpForbidden); + HANDLE_CASE(kHttpTimeout); + HANDLE_CASE(kHttpConflict); + HANDLE_CASE(kHttpNoHost); + HANDLE_CASE(kHttpOtherServerError); + HANDLE_CASE(kHttpInternalServerError); + HANDLE_CASE(kHttpServiceUnavailable); + HANDLE_CASE(kHttpBadGateway); + HANDLE_CASE(kHttpGatewayTimeout); +#undef HANDLE_CASE + + default: + return ReturnCode::kOtherError; } } @@ -1093,7 +1063,7 @@ main(int argc, char** argv) catch (const HttpClientError& Ex) { ZEN_CONSOLE_ERROR("Operation failed due to a http error: {}", Ex.what()); - ReturnCode Result = GetReturnCodeFromHttpResult(Ex.m_Error, Ex.m_ResponseCode); + ReturnCode Result = GetReturnCodeFromHttpResult(Ex); return (int)Result; } catch (const AssertException& Ex) @@ -1144,7 +1114,7 @@ main(int argc, char** argv) catch (const HttpClientError& Ex) { printf("Error: Operation failed due to a http error: %s", Ex.what()); - ReturnCode Result = GetReturnCodeFromHttpResult(Ex.m_Error, Ex.m_ResponseCode); + ReturnCode Result = GetReturnCodeFromHttpResult(Ex); return (int)Result; } catch (const AssertException& Ex) diff --git a/src/zencore/include/zencore/string.h b/src/zencore/include/zencore/string.h index 68129b691..93f8add0a 100644 --- a/src/zencore/include/zencore/string.h +++ b/src/zencore/include/zencore/string.h @@ -679,6 +679,9 @@ ParseHexNumber(const std::string_view HexString, UnsignedIntegral auto& OutValue return ParseHexNumber(HexString.data(), ExpectedCharacterCount, (uint8_t*)&OutValue); } +void UrlDecode(std::string_view InUrl, StringBuilderBase& OutUrl); +std::string UrlDecode(std::string_view InUrl); + ////////////////////////////////////////////////////////////////////////// // Format numbers for humans // diff --git a/src/zencore/string.cpp b/src/zencore/string.cpp index a0d8c927f..c8c7c2cde 100644 --- a/src/zencore/string.cpp +++ b/src/zencore/string.cpp @@ -483,12 +483,67 @@ template class StringBuilderImpl<char>; template class StringBuilderImpl<wchar_t>; ////////////////////////////////////////////////////////////////////////// + +void +UrlDecode(std::string_view InUrl, StringBuilderBase& OutUrl) +{ + std::string_view::size_type i = 0; + + for (; i != InUrl.size();) + { + char c = InUrl[i]; + + if ((c == '%') && ((i + 2) < InUrl.size())) + { + char hex[2] = {InUrl[i + 1], InUrl[i + 2]}; + uint8_t HexedChar; + if (ParseHexBytes(hex, 2, &HexedChar)) + { + OutUrl.Append(HexedChar); + i += 3; + + continue; + } + } + + OutUrl.Append(c); + ++i; + } +} + +std::string +UrlDecode(std::string_view InUrl) +{ + ExtendableStringBuilder<128> Url; + UrlDecode(InUrl, Url); + + return std::string(Url.ToView()); +} + +////////////////////////////////////////////////////////////////////////// // // Unit tests // #if ZEN_WITH_TESTS +TEST_CASE("url") +{ + using namespace std::literals; + + ExtendableStringBuilder<32> OutUrl; + UrlDecode("http://blah.com/foo?bar=hi%20ho", OutUrl); + CHECK_EQ(OutUrl.ToView(), "http://blah.com/foo?bar=hi ho"sv); + + OutUrl.Reset(); + + UrlDecode("http://blah.com/foo?bar=hi%ho", OutUrl); + CHECK_EQ(OutUrl.ToView(), "http://blah.com/foo?bar=hi%ho"sv); + + CHECK_EQ(UrlDecode("http://blah.com/foo?bar=hi%20ho"), "http://blah.com/foo?bar=hi ho"sv); + CHECK_EQ(UrlDecode("http://blah.com/foo?bar=hi%ho"), "http://blah.com/foo?bar=hi%ho"sv); +} + TEST_CASE("niceNum") { char Buffer[16]; diff --git a/src/zenhttp/auth/oidc.cpp b/src/zenhttp/auth/oidc.cpp index 318110c7d..38e7586ad 100644 --- a/src/zenhttp/auth/oidc.cpp +++ b/src/zenhttp/auth/oidc.cpp @@ -1,9 +1,9 @@ // Copyright Epic Games, Inc. All Rights Reserved. #include "zenhttp/auth/oidc.h" +#include <zenhttp/httpclient.h> ZEN_THIRD_PARTY_INCLUDES_START -#include <cpr/cpr.h> #include <fmt/format.h> #include <json11.hpp> ZEN_THIRD_PARTY_INCLUDES_END @@ -41,27 +41,21 @@ OidcClient::OidcClient(const OidcClient::Options& Options) OidcClient::InitResult OidcClient::Initialize() { - ExtendableStringBuilder<256> Uri; - Uri << m_BaseUrl << "/.well-known/openid-configuration"sv; + HttpClient Http{m_BaseUrl}; + HttpClient::Response Response = Http.Get("/.well-known/openid-configuration"sv); - cpr::Session Session; - - Session.SetOption(cpr::Url{Uri.c_str()}); - - cpr::Response Response = Session.Get(); - - if (Response.error) + if (!Response) { - return {.Reason = std::move(Response.error.message)}; + return {.Reason = Response.ErrorMessage("")}; } - if (Response.status_code != 200) + if (Response.StatusCode != HttpResponseCode::OK) { - return {.Reason = std::move(Response.reason)}; + return {.Reason = std::string{ToString(Response.StatusCode)}}; } std::string JsonError; - json11::Json Json = json11::Json::parse(Response.text, JsonError); + json11::Json Json = json11::Json::parse(std::string{Response.AsText()}, JsonError); if (JsonError.empty() == false) { @@ -89,26 +83,24 @@ OidcClient::RefreshToken(std::string_view RefreshToken) { const std::string Body = fmt::format("grant_type=refresh_token&refresh_token={}&client_id={}", RefreshToken, m_ClientId); - cpr::Session Session; + HttpClient Http{m_Config.TokenEndpoint}; - Session.SetOption(cpr::Url{m_Config.TokenEndpoint.c_str()}); - Session.SetOption(cpr::Header{{"Content-Type", "application/x-www-form-urlencoded"}}); - Session.SetBody(cpr::Body{Body.data(), Body.size()}); + HttpClient::KeyValueMap Headers{{"Content-Type", "application/x-www-form-urlencoded"}}; - cpr::Response Response = Session.Post(); + HttpClient::Response Response = Http.Post("", IoBufferBuilder::MakeFromMemory(MemoryView{Body.data(), Body.size()}), Headers); - if (Response.error) + if (!Response) { - return {.Reason = std::move(Response.error.message)}; + return {.Reason = std::string{Response.ErrorMessage("")}}; } - if (Response.status_code != 200) + if (Response.StatusCode != HttpResponseCode::OK) { - return {.Reason = fmt::format("{} ({})", Response.reason, Response.text)}; + return {.Reason = fmt::format("{} ({})", ToString(Response.StatusCode), Response.AsText())}; } std::string JsonError; - json11::Json Json = json11::Json::parse(Response.text, JsonError); + json11::Json Json = json11::Json::parse(std::string{Response.AsText()}, JsonError); if (JsonError.empty() == false) { diff --git a/src/zenhttp/httpclient.cpp b/src/zenhttp/httpclient.cpp index 9ee8cc05a..5981d449a 100644 --- a/src/zenhttp/httpclient.cpp +++ b/src/zenhttp/httpclient.cpp @@ -1,5 +1,6 @@ // Copyright Epic Games, Inc. All Rights Reserved. +#include <zenhttp/cprutils.h> #include <zenhttp/formatters.h> #include <zenhttp/httpclient.h> #include <zenhttp/httpserver.h> @@ -27,7 +28,8 @@ #endif // ZEN_WITH_TESTS ZEN_THIRD_PARTY_INCLUDES_START -#include <cpr/cpr.h> +#include <cpr/body.h> +#include <cpr/session.h> ZEN_THIRD_PARTY_INCLUDES_END #if ZEN_PLATFORM_LINUX || ZEN_PLATFORM_MAC @@ -1660,6 +1662,72 @@ HttpClient::Response::ThrowError(std::string_view ErrorPrefix) ////////////////////////////////////////////////////////////////////////// +HttpClientError::ResponseClass +HttpClientError::GetResponseClass() const +{ + if ((cpr::ErrorCode)m_Error != cpr::ErrorCode::OK) + { + switch ((cpr::ErrorCode)m_Error) + { + case cpr::ErrorCode::CONNECTION_FAILURE: + return ResponseClass::kHttpCantConnectError; + case cpr::ErrorCode::HOST_RESOLUTION_FAILURE: + case cpr::ErrorCode::PROXY_RESOLUTION_FAILURE: + return ResponseClass::kHttpNoHost; + case cpr::ErrorCode::INTERNAL_ERROR: + case cpr::ErrorCode::NETWORK_RECEIVE_ERROR: + case cpr::ErrorCode::NETWORK_SEND_FAILURE: + case cpr::ErrorCode::OPERATION_TIMEDOUT: + return ResponseClass::kHttpTimeout; + case cpr::ErrorCode::SSL_CONNECT_ERROR: + case cpr::ErrorCode::SSL_LOCAL_CERTIFICATE_ERROR: + case cpr::ErrorCode::SSL_REMOTE_CERTIFICATE_ERROR: + case cpr::ErrorCode::SSL_CACERT_ERROR: + case cpr::ErrorCode::GENERIC_SSL_ERROR: + return ResponseClass::kHttpSLLError; + default: + return ResponseClass::kHttpOtherClientError; + } + } + else if (IsHttpSuccessCode(m_ResponseCode)) + { + return ResponseClass::kSuccess; + } + else + { + switch (m_ResponseCode) + { + case HttpResponseCode::Unauthorized: + return ResponseClass::kHttpUnauthorized; + case HttpResponseCode::NotFound: + return ResponseClass::kHttpNotFound; + case HttpResponseCode::Forbidden: + return ResponseClass::kHttpForbidden; + case HttpResponseCode::Conflict: + return ResponseClass::kHttpConflict; + case HttpResponseCode::InternalServerError: + return ResponseClass::kHttpInternalServerError; + case HttpResponseCode::ServiceUnavailable: + return ResponseClass::kHttpServiceUnavailable; + case HttpResponseCode::BadGateway: + return ResponseClass::kHttpBadGateway; + case HttpResponseCode::GatewayTimeout: + return ResponseClass::kHttpGatewayTimeout; + default: + if (m_ResponseCode >= HttpResponseCode::InternalServerError) + { + return ResponseClass::kHttpOtherServerError; + } + else + { + return ResponseClass::kHttpOtherClientError; + } + } + } +} + +////////////////////////////////////////////////////////////////////////// + #if ZEN_WITH_TESTS namespace testutil { diff --git a/src/zenhttp/httpclientauth.cpp b/src/zenhttp/httpclientauth.cpp index 4bbc6405b..4438fc137 100644 --- a/src/zenhttp/httpclientauth.cpp +++ b/src/zenhttp/httpclientauth.cpp @@ -9,11 +9,11 @@ #include <zencore/timer.h> #include <zencore/uid.h> #include <zenhttp/auth/authmgr.h> +#include <zenhttp/httpclient.h> #include <ctime> ZEN_THIRD_PARTY_INCLUDES_START -#include <cpr/cpr.h> #include <fmt/format.h> #include <json11.hpp> ZEN_THIRD_PARTY_INCLUDES_END @@ -47,18 +47,22 @@ namespace zen { namespace httpclientauth { OAuthParams.ClientId, OAuthParams.ClientSecret); - cpr::Response Response = cpr::Post(cpr::Url{OAuthParams.Url}, - cpr::Header{{"Content-Type", "application/x-www-form-urlencoded"}}, - cpr::Body{std::move(Body)}); + HttpClient Http{OAuthParams.Url}; - if (Response.error || Response.status_code != 200) + IoBuffer Payload{IoBuffer::Wrap, Body.data(), Body.size()}; + + // TODO: ensure this gets the right Content-Type passed along + + HttpClient::Response Response = Http.Post("", Payload, {{"Content-Type", "application/x-www-form-urlencoded"}}); + + if (!Response || Response.StatusCode != HttpResponseCode::OK) { - ZEN_WARN("Failed fetching OAuth access token {}. Reason: '{}'", OAuthParams.Url, Response.reason); + ZEN_WARN("Failed fetching OAuth access token {}. Reason: '{}'", OAuthParams.Url, Response.ErrorMessage("")); return HttpClientAccessToken{}; } std::string JsonError; - json11::Json Json = json11::Json::parse(Response.text, JsonError); + json11::Json Json = json11::Json::parse(std::string{Response.AsText()}, JsonError); if (JsonError.empty() == false) { diff --git a/src/zenhttp/include/zenhttp/cprutils.h b/src/zenhttp/include/zenhttp/cprutils.h new file mode 100644 index 000000000..a3b870c0f --- /dev/null +++ b/src/zenhttp/include/zenhttp/cprutils.h @@ -0,0 +1,86 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include <zencore/compactbinary.h> +#include <zencore/compactbinaryvalidation.h> +#include <zencore/iobuffer.h> +#include <zencore/string.h> +#include <zenhttp/formatters.h> +#include <zenhttp/httpclient.h> +#include <zenhttp/httpcommon.h> + +ZEN_THIRD_PARTY_INCLUDES_START +#include <cpr/response.h> +#include <fmt/format.h> +ZEN_THIRD_PARTY_INCLUDES_END + +template<> +struct fmt::formatter<cpr::Response> +{ + constexpr auto parse(format_parse_context& Ctx) -> decltype(Ctx.begin()) { return Ctx.end(); } + + template<typename FormatContext> + auto format(const cpr::Response& Response, FormatContext& Ctx) const -> decltype(Ctx.out()) + { + using namespace std::literals; + + zen::NiceTimeSpanMs NiceResponseTime(uint64_t(Response.elapsed * 1000)); + + if (zen::IsHttpSuccessCode(Response.status_code)) + { + return fmt::format_to(Ctx.out(), + "Url: {}, Status: {}, Error: '{}' ({}), Bytes: {}/{} (Up/Down), Elapsed: {}", + Response.url.str(), + Response.status_code, + Response.error.message, + int(Response.error.code), + Response.uploaded_bytes, + Response.downloaded_bytes, + NiceResponseTime.c_str()); + } + else + { + const auto It = Response.header.find("Content-Type"); + const std::string_view ContentType = It != Response.header.end() ? It->second : "<None>"sv; + + if (ContentType == "application/x-ue-cb"sv) + { + zen::IoBuffer Body(zen::IoBuffer::Wrap, Response.text.data(), Response.text.size()); + zen::CbObjectView Obj(Body.Data()); + zen::ExtendableStringBuilder<256> Sb; + std::string_view Json = Obj.ToJson(Sb).ToView(); + + return fmt::format_to( + Ctx.out(), + "Url: {}, Status: {}, Error: '{}' ({}). Bytes: {}/{} (Up/Down), Elapsed: {}, Response: '{}', Reason: '{}'", + Response.url.str(), + Response.status_code, + Response.error.message, + int(Response.error.code), + Response.uploaded_bytes, + Response.downloaded_bytes, + NiceResponseTime.c_str(), + Json, + Response.reason); + } + else + { + zen::BodyLogFormatter Body(Response.text); + + return fmt::format_to( + Ctx.out(), + "Url: {}, Status: {}, Error: '{}' ({}), Bytes: {}/{} (Up/Down), Elapsed: {}, Response: '{}', Reason: '{}'", + Response.url.str(), + Response.status_code, + Response.error.message, + int(Response.error.code), + Response.uploaded_bytes, + Response.downloaded_bytes, + NiceResponseTime.c_str(), + Body.GetText(), + Response.reason); + } + } + } +}; diff --git a/src/zenhttp/include/zenhttp/formatters.h b/src/zenhttp/include/zenhttp/formatters.h index 05a23d675..0af31fa30 100644 --- a/src/zenhttp/include/zenhttp/formatters.h +++ b/src/zenhttp/include/zenhttp/formatters.h @@ -10,7 +10,6 @@ #include <zenhttp/httpcommon.h> ZEN_THIRD_PARTY_INCLUDES_START -#include <cpr/cpr.h> #include <fmt/format.h> ZEN_THIRD_PARTY_INCLUDES_END @@ -59,76 +58,6 @@ public: } // namespace zen template<> -struct fmt::formatter<cpr::Response> -{ - constexpr auto parse(format_parse_context& Ctx) -> decltype(Ctx.begin()) { return Ctx.end(); } - - template<typename FormatContext> - auto format(const cpr::Response& Response, FormatContext& Ctx) const -> decltype(Ctx.out()) - { - using namespace std::literals; - - zen::NiceTimeSpanMs NiceResponseTime(uint64_t(Response.elapsed * 1000)); - - if (zen::IsHttpSuccessCode(Response.status_code)) - { - return fmt::format_to(Ctx.out(), - "Url: {}, Status: {}, Error: '{}' ({}), Bytes: {}/{} (Up/Down), Elapsed: {}", - Response.url.str(), - Response.status_code, - Response.error.message, - int(Response.error.code), - Response.uploaded_bytes, - Response.downloaded_bytes, - NiceResponseTime.c_str()); - } - else - { - const auto It = Response.header.find("Content-Type"); - const std::string_view ContentType = It != Response.header.end() ? It->second : "<None>"sv; - - if (ContentType == "application/x-ue-cb"sv) - { - zen::IoBuffer Body(zen::IoBuffer::Wrap, Response.text.data(), Response.text.size()); - zen::CbObjectView Obj(Body.Data()); - zen::ExtendableStringBuilder<256> Sb; - std::string_view Json = Obj.ToJson(Sb).ToView(); - - return fmt::format_to( - Ctx.out(), - "Url: {}, Status: {}, Error: '{}' ({}). Bytes: {}/{} (Up/Down), Elapsed: {}, Response: '{}', Reason: '{}'", - Response.url.str(), - Response.status_code, - Response.error.message, - int(Response.error.code), - Response.uploaded_bytes, - Response.downloaded_bytes, - NiceResponseTime.c_str(), - Json, - Response.reason); - } - else - { - zen::BodyLogFormatter Body(Response.text); - - return fmt::format_to( - Ctx.out(), - "Url: {}, Status: {}, Error: '{}' ({}), Bytes: {}/{} (Up/Down), Elapsed: {}, Response: '{}', Reason: '{}'", - Response.url.str(), - Response.status_code, - Response.error.message, - int(Response.error.code), - Response.uploaded_bytes, - Response.downloaded_bytes, - NiceResponseTime.c_str(), - Body.GetText(), - Response.reason); - } - } - } -}; - -template<> struct fmt::formatter<zen::HttpClient::Response> { constexpr auto parse(format_parse_context& Ctx) -> decltype(Ctx.begin()) { return Ctx.end(); } diff --git a/src/zenhttp/include/zenhttp/httpclient.h b/src/zenhttp/include/zenhttp/httpclient.h index 50bd5b53a..ec06aa229 100644 --- a/src/zenhttp/include/zenhttp/httpclient.h +++ b/src/zenhttp/include/zenhttp/httpclient.h @@ -76,6 +76,34 @@ public: { } + inline int GetInternalErrorCode() const { return m_Error; } + inline HttpResponseCode GetHttpResponseCode() const { return m_ResponseCode; } + + enum class ResponseClass : std::int8_t + { + kSuccess = 0, + + kHttpOtherClientError = 80, + kHttpCantConnectError = 81, // CONNECTION_FAILURE + kHttpNotFound = 66, // NotFound(404) + kHttpUnauthorized = 77, // Unauthorized(401), + kHttpSLLError = + 82, // SSL_CONNECT_ERROR, SSL_LOCAL_CERTIFICATE_ERROR, SSL_REMOTE_CERTIFICATE_ERROR, SSL_CACERT_ERROR, GENERIC_SSL_ERROR + kHttpForbidden = 83, // Forbidden(403) + kHttpTimeout = 84, // NETWORK_RECEIVE_ERROR, NETWORK_SEND_FAILURE, OPERATION_TIMEDOUT, RequestTimeout(408) + kHttpConflict = 85, // Conflict(409) + kHttpNoHost = 86, // HOST_RESOLUTION_FAILURE, PROXY_RESOLUTION_FAILURE + + kHttpOtherServerError = 90, + kHttpInternalServerError = 91, // InternalServerError(500) + kHttpServiceUnavailable = 69, // ServiceUnavailable(503) + kHttpBadGateway = 92, // BadGateway(502) + kHttpGatewayTimeout = 93, // GatewayTimeout(504) + }; + + ResponseClass GetResponseClass() const; + +private: const int m_Error = 0; const HttpResponseCode m_ResponseCode = HttpResponseCode::ImATeapot; }; diff --git a/src/zenserver-test/projectclient.cpp b/src/zenserver-test/projectclient.cpp deleted file mode 100644 index cb493be77..000000000 --- a/src/zenserver-test/projectclient.cpp +++ /dev/null @@ -1,160 +0,0 @@ -// Copyright Epic Games, Inc. All Rights Reserved. - -#include "projectclient.h" - -#if 0 - -# include <zencore/compactbinary.h> -# include <zencore/logging.h> -# include <zencore/sharedbuffer.h> -# include <zencore/string.h> -# include <zencore/zencore.h> - -# include <asio.hpp> -# include <gsl/gsl-lite.hpp> - -namespace zen { - -struct ProjectClientConnection -{ - ProjectClientConnection(int BasePort) { Connect(BasePort); } - - void Connect(int BasePort) - { - ZEN_UNUSED(BasePort); - - WideStringBuilder<64> PipeName; - PipeName << "\\\\.\\pipe\\zenprj"; // TODO: this should use an instance-specific identifier! - - HANDLE hPipe = CreateFileW(PipeName.c_str(), - GENERIC_READ | GENERIC_WRITE, - 0, // Sharing doesn't make any sense - nullptr, // No security attributes - OPEN_EXISTING, // Open existing pipe - 0, // Attributes - nullptr // Template file - ); - - if (hPipe == INVALID_HANDLE_VALUE) - { - ZEN_WARN("failed while creating named pipe {}", WideToUtf8(PipeName)); - - throw std::system_error(GetLastError(), std::system_category(), fmt::format("Failed to open named pipe '{}'", WideToUtf8(PipeName))); - } - - // Change to message mode - DWORD dwMode = PIPE_READMODE_MESSAGE; - BOOL Success = SetNamedPipeHandleState(hPipe, &dwMode, nullptr, nullptr); - - if (!Success) - { - throw std::system_error(GetLastError(), - std::system_category(), - fmt::format("Failed to change named pipe '{}' to message mode", WideToUtf8(PipeName))); - } - - m_hPipe.Attach(hPipe); // This now owns the handle and will close it - } - - ~ProjectClientConnection() {} - - CbObject MessageTransaction(CbObject Request) - { - DWORD dwWrittenBytes = 0; - - MemoryView View = Request.GetView(); - - BOOL Success = ::WriteFile(m_hPipe, View.GetData(), gsl::narrow_cast<DWORD>(View.GetSize()), &dwWrittenBytes, nullptr); - - if (!Success) - { - throw std::system_error(GetLastError(), std::system_category(), "Failed to write pipe message"); - } - - ZEN_ASSERT(dwWrittenBytes == View.GetSize()); - - DWORD dwReadBytes = 0; - - Success = ReadFile(m_hPipe, m_Buffer, sizeof m_Buffer, &dwReadBytes, nullptr); - - if (!Success) - { - DWORD ErrorCode = GetLastError(); - - if (ERROR_MORE_DATA == ErrorCode) - { - // Response message is larger than our buffer - handle it by allocating a larger - // buffer on the heap and read the remainder into that buffer - - DWORD dwBytesAvail = 0, dwLeftThisMessage = 0; - - Success = PeekNamedPipe(m_hPipe, nullptr, 0, nullptr, &dwBytesAvail, &dwLeftThisMessage); - - if (Success) - { - UniqueBuffer MessageBuffer = UniqueBuffer::Alloc(dwReadBytes + dwLeftThisMessage); - - memcpy(MessageBuffer.GetData(), m_Buffer, dwReadBytes); - - Success = ReadFile(m_hPipe, - reinterpret_cast<uint8_t*>(MessageBuffer.GetData()) + dwReadBytes, - dwLeftThisMessage, - &dwReadBytes, - nullptr); - - if (Success) - { - return CbObject(SharedBuffer(std::move(MessageBuffer))); - } - } - } - - throw std::system_error(GetLastError(), std::system_category(), "Failed to read pipe message"); - } - - return CbObject(SharedBuffer::MakeView(MakeMemoryView(m_Buffer))); - } - -private: - static const int kEmbeddedBufferSize = 512 - 16; - - CHandle m_hPipe; - uint8_t m_Buffer[kEmbeddedBufferSize]; -}; - -struct LocalProjectClient::ClientImpl -{ - ClientImpl(int BasePort) : m_BasePort(BasePort) {} - ~ClientImpl() {} - - void Start() {} - void Stop() {} - - inline int BasePort() const { return m_BasePort; } - -private: - int m_BasePort = 0; -}; - -LocalProjectClient::LocalProjectClient(int BasePort) -{ - m_Impl = std::make_unique<ClientImpl>(BasePort); - m_Impl->Start(); -} - -LocalProjectClient::~LocalProjectClient() -{ - m_Impl->Stop(); -} - -CbObject -LocalProjectClient::MessageTransaction(CbObject Request) -{ - ProjectClientConnection Cx(m_Impl->BasePort()); - - return Cx.MessageTransaction(Request); -} - -} // namespace zen - -#endif // 0 diff --git a/src/zenserver-test/projectclient.h b/src/zenserver-test/projectclient.h deleted file mode 100644 index 8362ee0ee..000000000 --- a/src/zenserver-test/projectclient.h +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright Epic Games, Inc. All Rights Reserved. - -#pragma once - -#include <memory> - -#include <zenbase/refcount.h> -#include <zencore/compactbinary.h> - -namespace zen { - -/** - * Client for communication with local project service - * - * This is WIP and not yet functional! - */ - -class LocalProjectClient : public RefCounted -{ -public: - LocalProjectClient(int BasePort = 0); - ~LocalProjectClient(); - - CbObject MessageTransaction(CbObject Request); - -private: - struct ClientImpl; - - std::unique_ptr<ClientImpl> m_Impl; -}; - -} // namespace zen diff --git a/src/zenserver-test/zenserver-test.cpp b/src/zenserver-test/zenserver-test.cpp index 923d35d13..827a4eb5a 100644 --- a/src/zenserver-test/zenserver-test.cpp +++ b/src/zenserver-test/zenserver-test.cpp @@ -38,7 +38,6 @@ #endif ZEN_THIRD_PARTY_INCLUDES_START -#include <cpr/cpr.h> #include <tsl/robin_set.h> #undef GetObject ZEN_THIRD_PARTY_INCLUDES_END @@ -61,10 +60,6 @@ ZEN_THIRD_PARTY_INCLUDES_END ////////////////////////////////////////////////////////////////////////// -#include "projectclient.h" - -////////////////////////////////////////////////////////////////////////// - #if ZEN_WITH_TESTS # define ZEN_TEST_WITH_RUNNER 1 # include <zencore/testing.h> @@ -180,12 +175,12 @@ TEST_CASE("default.single") const int ThreadId = zen::GetCurrentThreadId(); ZEN_INFO("query batch {} started (thread {})", BatchNo, ThreadId); - cpr::Session cli; - cli.SetUrl(cpr::Url{fmt::format("http://localhost:{}/test/hello", PortNumber)}); + + HttpClient Http{fmt::format("http://localhost:{}", PortNumber)}; for (int i = 0; i < 10000; ++i) { - auto res = cli.Get(); + auto res = Http.Get("/test/hello"sv); ++RequestCount; } ZEN_INFO("query batch {} ended (thread {})", BatchNo, ThreadId); @@ -224,18 +219,20 @@ TEST_CASE("default.loopback") SUBCASE("ipv4 endpoint connectivity") { - cpr::Session cli; - cli.SetUrl(cpr::Url{fmt::format("http://127.0.0.1:{}/test/hello", PortNumber)}); - auto res = cli.Get(); - CHECK(!res.error); + HttpClient Http{fmt::format("http://127.0.0.1:{}", PortNumber)}; + + auto res = Http.Get("/test/hello"sv); + + CHECK(res); } SUBCASE("ipv6 endpoint connectivity") { - cpr::Session cli; - cli.SetUrl(cpr::Url{fmt::format("http://[::1]:{}/test/hello", PortNumber)}); - auto res = cli.Get(); - CHECK(!res.error); + HttpClient Http{fmt::format("http://[::1]:{}", PortNumber)}; + + auto res = Http.Get("/test/hello"sv); + + CHECK(res); } } @@ -267,14 +264,14 @@ TEST_CASE("multi.basic") ZEN_INFO("query batch {} started (thread {}) for port {}", BatchNo, ThreadId, PortNumber); - cpr::Session cli; - cli.SetUrl(cpr::Url{fmt::format("http://localhost:{}/test/hello", PortNumber)}); + HttpClient Http{fmt::format("http://localhost:{}", PortNumber)}; for (int i = 0; i < 10000; ++i) { - auto res = cli.Get(); + auto res = Http.Get("/test/hello"sv); ++RequestCount; } + ZEN_INFO("query batch {} ended (thread {})", BatchNo, ThreadId); }; @@ -306,14 +303,10 @@ TEST_CASE("project.basic") const uint16_t PortNumber = Instance1.SpawnServerAndWaitUntilReady(); - std::atomic<uint64_t> RequestCount{0}; - - zen::Stopwatch timer; - std::mt19937_64 mt; zen::StringBuilder<64> BaseUri; - BaseUri << fmt::format("http://localhost:{}/prj/test", PortNumber); + BaseUri << fmt::format("http://localhost:{}", PortNumber); std::filesystem::path BinPath = zen::GetRunningExecutablePath(); std::filesystem::path RootPath = BinPath.parent_path().parent_path(); @@ -322,6 +315,8 @@ TEST_CASE("project.basic") SUBCASE("build store init") { { + HttpClient Http{BaseUri}; + { zen::CbObjectWriter Body; Body << "id" @@ -333,38 +328,38 @@ TEST_CASE("project.basic") << "/zooom"; zen::BinaryWriter MemOut; - Body.Save(MemOut); + IoBuffer BodyBuf = Body.Save().GetBuffer().AsIoBuffer(); - auto Response = cpr::Post(cpr::Url{BaseUri.c_str()}, cpr::Body{(const char*)MemOut.Data(), MemOut.Size()}); - CHECK(Response.status_code == 201); + auto Response = Http.Post("/prj/test"sv, BodyBuf); + CHECK(Response.StatusCode == HttpResponseCode::Created); } { - auto Response = cpr::Get(cpr::Url{BaseUri.c_str()}); - CHECK(Response.status_code == 200); + auto Response = Http.Get("/prj/test"sv); + CHECK(Response.StatusCode == HttpResponseCode::OK); - zen::CbObjectView ResponseObject = zen::CbFieldView(Response.text.data()).AsObjectView(); + CbObject ResponseObject = Response.AsObject(); CHECK(ResponseObject["id"].AsString() == "test"sv); CHECK(ResponseObject["root"].AsString() == PathToUtf8(RootPath.c_str())); } } - BaseUri << "/oplog/foobar"; + BaseUri << "/prj/test/oplog/foobar"; { + HttpClient Http{BaseUri}; + { - zen::StringBuilder<64> PostUri; - PostUri << BaseUri; - auto Response = cpr::Post(cpr::Url{PostUri.c_str()}); - CHECK(Response.status_code == 201); + auto Response = Http.Post(""sv); + CHECK(Response.StatusCode == HttpResponseCode::Created); } { - auto Response = cpr::Get(cpr::Url{BaseUri.c_str()}); - CHECK(Response.status_code == 200); + auto Response = Http.Get(""sv); + CHECK(Response.StatusCode == HttpResponseCode::OK); - zen::CbObjectView ResponseObject = zen::CbFieldView(Response.text.data()).AsObjectView(); + CbObject ResponseObject = Response.AsObject(); CHECK(ResponseObject["id"].AsString() == "foobar"sv); CHECK(ResponseObject["project"].AsString() == "test"sv); @@ -406,34 +401,34 @@ TEST_CASE("project.basic") zen::BinaryWriter MemOut; legacy::SaveCbPackage(OpPackage, MemOut); + HttpClient Http{BaseUri}; + { - zen::StringBuilder<64> PostUri; - PostUri << BaseUri << "/new"; - auto Response = cpr::Post(cpr::Url{PostUri.c_str()}, cpr::Body{(const char*)MemOut.Data(), MemOut.Size()}); + auto Response = Http.Post("/new", IoBufferBuilder::MakeFromMemory(MemOut.GetView())); - REQUIRE(!Response.error); - CHECK(Response.status_code == 201); + REQUIRE(Response); + CHECK(Response.StatusCode == HttpResponseCode::Created); } // Read file data { zen::StringBuilder<128> ChunkGetUri; - ChunkGetUri << BaseUri << "/" << ChunkId; - auto Response = cpr::Get(cpr::Url{ChunkGetUri.c_str()}); + ChunkGetUri << "/" << ChunkId; + auto Response = Http.Get(ChunkGetUri); - REQUIRE(!Response.error); - CHECK(Response.status_code == 200); + REQUIRE(Response); + CHECK(Response.StatusCode == HttpResponseCode::OK); } { zen::StringBuilder<128> ChunkGetUri; - ChunkGetUri << BaseUri << "/" << ChunkId << "?offset=1&size=10"; - auto Response = cpr::Get(cpr::Url{ChunkGetUri.c_str()}); + ChunkGetUri << "/" << ChunkId << "?offset=1&size=10"; + auto Response = Http.Get(ChunkGetUri); - REQUIRE(!Response.error); - CHECK(Response.status_code == 200); - CHECK(Response.text.size() == 10); + REQUIRE(Response); + CHECK(Response.StatusCode == HttpResponseCode::OK); + CHECK(Response.ResponsePayload.GetSize() == 10); } ZEN_INFO("+++++++"); @@ -467,49 +462,47 @@ TEST_CASE("project.basic") zen::BinaryWriter MemOut; legacy::SaveCbPackage(OpPackage, MemOut); + HttpClient Http{BaseUri}; + { - zen::StringBuilder<64> PostUri; - PostUri << BaseUri << "/new"; - auto Response = cpr::Post(cpr::Url{PostUri.c_str()}, cpr::Body{(const char*)MemOut.Data(), MemOut.Size()}); + auto Response = Http.Post("/new", IoBufferBuilder::MakeFromMemory(MemOut.GetView())); - REQUIRE(!Response.error); - CHECK(Response.status_code == 201); + REQUIRE(Response); + CHECK(Response.StatusCode == HttpResponseCode::Created); } // Read file data, it is raw and uncompressed { zen::StringBuilder<128> ChunkGetUri; - ChunkGetUri << BaseUri << "/" << ChunkId; - auto Response = cpr::Get(cpr::Url{ChunkGetUri.c_str()}); + ChunkGetUri << "/" << ChunkId; + auto Response = Http.Get(ChunkGetUri); - REQUIRE(!Response.error); - CHECK(Response.status_code == 200); - IoBuffer Data(IoBuffer::Wrap, Response.text.data(), Response.text.length()); + REQUIRE(Response); + CHECK(Response.StatusCode == HttpResponseCode::OK); + + IoBuffer Data = Response.ResponsePayload; IoBuffer ReferenceData = IoBufferBuilder::MakeFromFile(RootPath / BinPath); CHECK(ReferenceData.GetSize() == Data.GetSize()); CHECK(ReferenceData.GetView().EqualBytes(Data.GetView())); } { - IoBuffer Payload = MakeCbObjectPayload([&](CbObjectWriter& Writer) { Writer.AddString("method"sv, "snapshot"sv); }); - zen::StringBuilder<64> PostUri; - PostUri << BaseUri << "/rpc"; - auto Response = cpr::Post(cpr::Url{PostUri.c_str()}, - cpr::Body{(const char*)Payload.Data(), Payload.Size()}, - cpr::Header{{"Content-Type", "application/x-ue-cb"}}); - REQUIRE(!Response.error); - CHECK(Response.status_code == 200); + IoBuffer Payload = MakeCbObjectPayload([&](CbObjectWriter& Writer) { Writer.AddString("method"sv, "snapshot"sv); }); + auto Response = Http.Post("/rpc"sv, Payload, {{"Content-Type", "application/x-ue-cb"}}); + REQUIRE(Response); + CHECK(Response.StatusCode == HttpResponseCode::OK); } // Read chunk data, it is now compressed { zen::StringBuilder<128> ChunkGetUri; - ChunkGetUri << BaseUri << "/" << ChunkId; - auto Response = cpr::Get(cpr::Url{ChunkGetUri.c_str()}, cpr::Header{{"Accept-Type", "application/x-ue-comp"}}); + ChunkGetUri << "/" << ChunkId; + auto Response = Http.Get(ChunkGetUri, {{"Accept-Type", "application/x-ue-comp"}}); + + REQUIRE(Response); + CHECK(Response.StatusCode == HttpResponseCode::OK); - REQUIRE(!Response.error); - CHECK(Response.status_code == 200); - IoBuffer Data(IoBuffer::Wrap, Response.text.data(), Response.text.length()); + IoBuffer Data = Response.ResponsePayload; IoHash RawHash; uint64_t RawSize; CompressedBuffer Compressed = CompressedBuffer::FromCompressed(SharedBuffer(Data), RawHash, RawSize); @@ -526,24 +519,19 @@ TEST_CASE("project.basic") SUBCASE("test chunk not found error") { + HttpClient Http{BaseUri}; + for (size_t I = 0; I < 65; I++) { zen::StringBuilder<128> PostUri; - PostUri << BaseUri << "/f77c781846caead318084604/info"; - auto Response = cpr::Get(cpr::Url{PostUri.c_str()}); + PostUri << "/f77c781846caead318084604/info"; + auto Response = Http.Get(PostUri); - REQUIRE(!Response.error); - CHECK(Response.status_code == 404); + REQUIRE(!Response.Error); + CHECK(Response.StatusCode == HttpResponseCode::NotFound); } } } - - const uint64_t Elapsed = timer.GetElapsedTimeMs(); - - ZEN_INFO("{} requests in {} ({})", - RequestCount.load(), - zen::NiceTimeSpanMs(Elapsed), - zen::NiceRate(RequestCount, (uint32_t)Elapsed, "req")); } namespace utils { @@ -664,33 +652,32 @@ TEST_CASE("zcache.basic") // Populate with some simple data + HttpClient Http{BaseUri}; + for (int i = 0; i < kIterationCount; ++i) { zen::CbObjectWriter Cbo; Cbo << "index" << i; - zen::BinaryWriter MemOut; - Cbo.Save(MemOut); + IoBuffer Payload = Cbo.Save().GetBuffer().AsIoBuffer(); + Payload.SetContentType(HttpContentType::kCbObject); zen::IoHash Key = HashKey(i); - cpr::Response Result = cpr::Put(cpr::Url{fmt::format("{}/{}/{}", BaseUri, "test", Key)}, - cpr::Body{(const char*)MemOut.Data(), MemOut.Size()}, - cpr::Header{{"Content-Type", "application/x-ue-cb"}}); + HttpClient::Response Result = Http.Put(fmt::format("/test/{}", Key), Payload); - CHECK(Result.status_code == 201); + CHECK(Result.StatusCode == HttpResponseCode::Created); } // Retrieve data for (int i = 0; i < kIterationCount; ++i) { - zen::IoHash Key = zen::IoHash::HashBuffer(&i, sizeof i); + zen::IoHash Key = HashKey(i); - cpr::Response Result = - cpr::Get(cpr::Url{fmt::format("{}/{}/{}", BaseUri, "test", Key)}, cpr::Header{{"Accept", "application/x-ue-cbpkg"}}); + HttpClient::Response Result = Http.Get(fmt::format("/test/{}", Key), {{"Accept", "application/x-ue-cbpkg"}}); - CHECK(Result.status_code == 200); + CHECK(Result.StatusCode == HttpResponseCode::OK); } // Ensure bad bucket identifiers are rejected @@ -699,16 +686,14 @@ TEST_CASE("zcache.basic") zen::CbObjectWriter Cbo; Cbo << "index" << 42; - zen::BinaryWriter MemOut; - Cbo.Save(MemOut); + IoBuffer Payload = Cbo.Save().GetBuffer().AsIoBuffer(); + Payload.SetContentType(HttpContentType::kCbObject); zen::IoHash Key = HashKey(442); - cpr::Response Result = cpr::Put(cpr::Url{fmt::format("{}/{}/{}", BaseUri, "te!st", Key)}, - cpr::Body{(const char*)MemOut.Data(), MemOut.Size()}, - cpr::Header{{"Content-Type", "application/x-ue-cb"}}); + HttpClient::Response Result = Http.Put(fmt::format("/te!st/{}", Key), Payload); - CHECK(Result.status_code == 400); + CHECK(Result.StatusCode == HttpResponseCode::BadRequest); } } @@ -721,20 +706,33 @@ TEST_CASE("zcache.basic") const std::string BaseUri = fmt::format("http://localhost:{}/z$", PortNumber); + HttpClient Http{BaseUri}; + // Retrieve data again for (int i = 0; i < kIterationCount; ++i) { zen::IoHash Key = HashKey(i); - cpr::Response Result = - cpr::Get(cpr::Url{fmt::format("{}/{}/{}", BaseUri, "test", Key)}, cpr::Header{{"Accept", "application/x-ue-cbpkg"}}); + HttpClient::Response Result = Http.Get(fmt::format("/{}/{}", "test", Key), {{"Accept", "application/x-ue-cbpkg"}}); - CHECK(Result.status_code == 200); + CHECK(Result.StatusCode == HttpResponseCode::OK); } } } +IoBuffer +SerializeToBuffer(const zen::CbPackage& Package) +{ + BinaryWriter MemStream; + + Package.Save(MemStream); + + IoBuffer Buffer = zen::IoBuffer(zen::IoBuffer::Clone, MemStream.Data(), MemStream.Size()); + Buffer.SetContentType(HttpContentType::kCbPackage); + return Buffer; +}; + TEST_CASE("zcache.cbpackage") { using namespace std::literals; @@ -757,14 +755,6 @@ TEST_CASE("zcache.cbpackage") return Package; }; - auto SerializeToBuffer = [](zen::CbPackage Package) -> zen::IoBuffer { - zen::BinaryWriter MemStream; - - Package.Save(MemStream); - - return zen::IoBuffer(zen::IoBuffer::Clone, MemStream.Data(), MemStream.Size()); - }; - auto IsEqual = [](zen::CbPackage Lhs, zen::CbPackage Rhs) -> bool { std::span<const zen::CbAttachment> LhsAttachments = Lhs.GetAttachments(); std::span<const zen::CbAttachment> RhsAttachments = Rhs.GetAttachments(); @@ -803,29 +793,26 @@ TEST_CASE("zcache.cbpackage") const uint16_t PortNumber = Instance1.SpawnServerAndWaitUntilReady(); const std::string BaseUri = fmt::format("http://localhost:{}/z$", PortNumber); + HttpClient Http{BaseUri}; + const std::string_view Bucket = "mosdef"sv; zen::IoHash Key; zen::CbPackage ExpectedPackage = CreateTestPackage(Key); // PUT { - zen::IoBuffer Body = SerializeToBuffer(ExpectedPackage); - cpr::Response Result = cpr::Put(cpr::Url{fmt::format("{}/{}/{}", BaseUri, Bucket, Key)}, - cpr::Body{(const char*)Body.Data(), Body.Size()}, - cpr::Header{{"Content-Type", "application/x-ue-cbpkg"}}); - CHECK(Result.status_code == 201); + zen::IoBuffer Body = SerializeToBuffer(ExpectedPackage); + HttpClient::Response Result = Http.Put(fmt::format("/{}/{}", Bucket, Key), Body); + CHECK(Result.StatusCode == HttpResponseCode::Created); } // GET { - cpr::Response Result = - cpr::Get(cpr::Url{fmt::format("{}/{}/{}", BaseUri, Bucket, Key)}, cpr::Header{{"Accept", "application/x-ue-cbpkg"}}); - CHECK(Result.status_code == 200); - - zen::IoBuffer Response(zen::IoBuffer::Wrap, Result.text.data(), Result.text.size()); + HttpClient::Response Result = Http.Get(fmt::format("/{}/{}", Bucket, Key), {{"Accept", "application/x-ue-cbpkg"}}); + CHECK(Result.StatusCode == HttpResponseCode::OK); zen::CbPackage Package; - const bool Ok = Package.TryLoad(Response); + const bool Ok = Package.TryLoad(Result.ResponsePayload); CHECK(Ok); CHECK(IsEqual(Package, ExpectedPackage)); } @@ -855,38 +842,35 @@ TEST_CASE("zcache.cbpackage") zen::IoHash Key; zen::CbPackage ExpectedPackage = CreateTestPackage(Key); + HttpClient LocalHttp{LocalBaseUri}; + HttpClient RemoteHttp{RemoteBaseUri}; + // Store the cache record package in the local instance { - zen::IoBuffer Body = SerializeToBuffer(ExpectedPackage); - cpr::Response Result = cpr::Put(cpr::Url{fmt::format("{}/{}/{}", LocalBaseUri, Bucket, Key)}, - cpr::Body{(const char*)Body.Data(), Body.Size()}, - cpr::Header{{"Content-Type", "application/x-ue-cbpkg"}}); + zen::IoBuffer Body = SerializeToBuffer(ExpectedPackage); + HttpClient::Response Result = LocalHttp.Put(fmt::format("/{}/{}", Bucket, Key), Body); - CHECK(Result.status_code == 201); + CHECK(Result.StatusCode == HttpResponseCode::Created); } // The cache record can be retrieved as a package from the local instance { - cpr::Response Result = - cpr::Get(cpr::Url{fmt::format("{}/{}/{}", LocalBaseUri, Bucket, Key)}, cpr::Header{{"Accept", "application/x-ue-cbpkg"}}); - CHECK(Result.status_code == 200); + HttpClient::Response Result = LocalHttp.Get(fmt::format("/{}/{}", Bucket, Key), {{"Accept", "application/x-ue-cbpkg"}}); + CHECK(Result.StatusCode == HttpResponseCode::OK); - zen::IoBuffer Body(zen::IoBuffer::Wrap, Result.text.data(), Result.text.size()); zen::CbPackage Package; - const bool Ok = Package.TryLoad(Body); + const bool Ok = Package.TryLoad(Result.ResponsePayload); CHECK(Ok); CHECK(IsEqual(Package, ExpectedPackage)); } // The cache record can be retrieved as a package from the remote instance { - cpr::Response Result = - cpr::Get(cpr::Url{fmt::format("{}/{}/{}", RemoteBaseUri, Bucket, Key)}, cpr::Header{{"Accept", "application/x-ue-cbpkg"}}); - CHECK(Result.status_code == 200); + HttpClient::Response Result = RemoteHttp.Get(fmt::format("/{}/{}", Bucket, Key), {{"Accept", "application/x-ue-cbpkg"}}); + CHECK(Result.StatusCode == HttpResponseCode::OK); - zen::IoBuffer Body(zen::IoBuffer::Wrap, Result.text.data(), Result.text.size()); zen::CbPackage Package; - const bool Ok = Package.TryLoad(Body); + const bool Ok = Package.TryLoad(Result.ResponsePayload); CHECK(Ok); CHECK(IsEqual(Package, ExpectedPackage)); } @@ -912,29 +896,28 @@ TEST_CASE("zcache.cbpackage") const auto LocalBaseUri = fmt::format("http://localhost:{}/z$", LocalPortNumber); const auto RemoteBaseUri = fmt::format("http://localhost:{}/z$", RemotePortNumber); + HttpClient LocalHttp{LocalBaseUri}; + HttpClient RemoteHttp{RemoteBaseUri}; + const std::string_view Bucket = "mosdef"sv; zen::IoHash Key; zen::CbPackage ExpectedPackage = CreateTestPackage(Key); // Store the cache record package in upstream cache { - zen::IoBuffer Body = SerializeToBuffer(ExpectedPackage); - cpr::Response Result = cpr::Put(cpr::Url{fmt::format("{}/{}/{}", RemoteBaseUri, Bucket, Key)}, - cpr::Body{(const char*)Body.Data(), Body.Size()}, - cpr::Header{{"Content-Type", "application/x-ue-cbpkg"}}); + zen::IoBuffer Body = SerializeToBuffer(ExpectedPackage); + HttpClient::Response Result = RemoteHttp.Put(fmt::format("/{}/{}", Bucket, Key), Body); - CHECK(Result.status_code == 201); + CHECK(Result.StatusCode == HttpResponseCode::Created); } // The cache record can be retrieved as a package from the local cache { - cpr::Response Result = - cpr::Get(cpr::Url{fmt::format("{}/{}/{}", LocalBaseUri, Bucket, Key)}, cpr::Header{{"Accept", "application/x-ue-cbpkg"}}); - CHECK(Result.status_code == 200); + HttpClient::Response Result = LocalHttp.Get(fmt::format("/{}/{}", Bucket, Key), {{"Accept", "application/x-ue-cbpkg"}}); + CHECK(Result.StatusCode == HttpResponseCode::OK); - zen::IoBuffer Body(zen::IoBuffer::Wrap, Result.text.data(), Result.text.size()); zen::CbPackage Package; - const bool Ok = Package.TryLoad(Body); + const bool Ok = Package.TryLoad(Result.ResponsePayload); CHECK(Ok); CHECK(IsEqual(Package, ExpectedPackage)); } @@ -946,7 +929,7 @@ TEST_CASE("zcache.policy") using namespace std::literals; using namespace utils; - auto GenerateData = [](uint64_t Size, zen::IoHash& OutHash) -> zen::UniqueBuffer { + auto GenerateData = [](uint64_t Size, zen::IoHash& OutHash) -> zen::IoBuffer { auto Buf = zen::UniqueBuffer::Alloc(Size); uint8_t* Data = reinterpret_cast<uint8_t*>(Buf.GetData()); for (uint64_t Idx = 0; Idx < Size; Idx++) @@ -954,7 +937,7 @@ TEST_CASE("zcache.policy") Data[Idx] = Idx % 256; } OutHash = zen::IoHash::HashBuffer(Data, Size); - return Buf; + return Buf.MoveToShared().AsIoBuffer(); }; auto GeneratePackage = [](zen::IoHash& OutRecordKey, zen::IoHash& OutAttachmentKey) -> zen::CbPackage { @@ -977,13 +960,6 @@ TEST_CASE("zcache.policy") return Package; }; - auto ToBuffer = [](zen::CbPackage Package) -> zen::IoBuffer { - zen::BinaryWriter MemStream; - Package.Save(MemStream); - - return zen::IoBuffer(zen::IoBuffer::Clone, MemStream.Data(), MemStream.Size()); - }; - SUBCASE("query - 'local' does not query upstream (binary)") { ZenConfig UpstreamCfg = ZenConfig::New(TestEnv.GetNewPortNumber()); @@ -998,26 +974,26 @@ TEST_CASE("zcache.policy") const std::string_view Bucket = "legacy"sv; zen::IoHash Key; - auto BinaryValue = GenerateData(1024, Key); + IoBuffer BinaryValue = GenerateData(1024, Key); + + HttpClient LocalHttp{LocalCfg.BaseUri}; + HttpClient RemoteHttp{UpstreamCfg.BaseUri}; - // Store binary cache value upstream { - cpr::Response Result = cpr::Put(cpr::Url{fmt::format("{}/{}/{}", UpstreamCfg.BaseUri, Bucket, Key)}, - cpr::Body{(const char*)BinaryValue.GetData(), BinaryValue.GetSize()}, - cpr::Header{{"Content-Type", "application/octet-stream"}}); - CHECK(Result.status_code == 201); + HttpClient::Response Result = RemoteHttp.Put(fmt::format("/{}/{}", Bucket, Key), BinaryValue); + CHECK(Result.StatusCode == HttpResponseCode::Created); } { - cpr::Response Result = cpr::Get(cpr::Url{fmt::format("{}/{}/{}?Policy=QueryLocal,Store", LocalCfg.BaseUri, Bucket, Key)}, - cpr::Header{{"Accept", "application/octet-stream"}}); - CHECK(Result.status_code == 404); + HttpClient::Response Result = + LocalHttp.Get(fmt::format("/{}/{}?Policy=QueryLocal,Store", Bucket, Key), {{"Accept", "application/octet-stream"}}); + CHECK(Result.StatusCode == HttpResponseCode::NotFound); } { - cpr::Response Result = cpr::Get(cpr::Url{fmt::format("{}/{}/{}?Policy=Query,Store", LocalCfg.BaseUri, Bucket, Key)}, - cpr::Header{{"Accept", "application/octet-stream"}}); - CHECK(Result.status_code == 200); + HttpClient::Response Result = + LocalHttp.Get(fmt::format("/{}/{}?Policy=Query,Store", Bucket, Key), {{"Accept", "application/octet-stream"}}); + CHECK(Result.StatusCode == HttpResponseCode::OK); } } @@ -1035,26 +1011,27 @@ TEST_CASE("zcache.policy") const auto Bucket = "legacy"sv; zen::IoHash Key; - auto BinaryValue = GenerateData(1024, Key); + IoBuffer BinaryValue = GenerateData(1024, Key); + + HttpClient LocalHttp{LocalCfg.BaseUri}; + HttpClient RemoteHttp{UpstreamCfg.BaseUri}; // Store binary cache value locally { - cpr::Response Result = cpr::Put(cpr::Url{fmt::format("{}/{}/{}?Policy=Query,StoreLocal", LocalCfg.BaseUri, Bucket, Key)}, - cpr::Body{(const char*)BinaryValue.GetData(), BinaryValue.GetSize()}, - cpr::Header{{"Content-Type", "application/octet-stream"}}); - CHECK(Result.status_code == 201); + HttpClient::Response Result = LocalHttp.Put(fmt::format("/{}/{}?Policy=Query,StoreLocal", Bucket, Key), + BinaryValue, + {{"Content-Type", "application/octet-stream"}}); + CHECK(Result.StatusCode == HttpResponseCode::Created); } { - cpr::Response Result = cpr::Get(cpr::Url{fmt::format("{}/{}/{}", UpstreamCfg.BaseUri, Bucket, Key)}, - cpr::Header{{"Accept", "application/octet-stream"}}); - CHECK(Result.status_code == 404); + HttpClient::Response Result = RemoteHttp.Get(fmt::format("/{}/{}", Bucket, Key), {{"Accept", "application/octet-stream"}}); + CHECK(Result.StatusCode == HttpResponseCode::NotFound); } { - cpr::Response Result = cpr::Get(cpr::Url{fmt::format("{}/{}/{}", LocalCfg.BaseUri, Bucket, Key)}, - cpr::Header{{"Accept", "application/octet-stream"}}); - CHECK(Result.status_code == 200); + HttpClient::Response Result = LocalHttp.Get(fmt::format("/{}/{}", Bucket, Key), {{"Accept", "application/octet-stream"}}); + CHECK(Result.StatusCode == HttpResponseCode::OK); } } @@ -1071,30 +1048,31 @@ TEST_CASE("zcache.policy") const auto Bucket = "legacy"sv; zen::IoHash Key; - auto BinaryValue = GenerateData(1024, Key); + IoBuffer BinaryValue = GenerateData(1024, Key); + + HttpClient LocalHttp{LocalCfg.BaseUri}; + HttpClient RemoteHttp{UpstreamCfg.BaseUri}; // Store binary cache value locally and upstream { - cpr::Response Result = cpr::Put(cpr::Url{fmt::format("{}/{}/{}?Policy=Query,Store", LocalCfg.BaseUri, Bucket, Key)}, - cpr::Body{(const char*)BinaryValue.GetData(), BinaryValue.GetSize()}, - cpr::Header{{"Content-Type", "application/octet-stream"}}); - CHECK(Result.status_code == 201); + HttpClient::Response Result = LocalHttp.Put(fmt::format("/{}/{}?Policy=Query,Store", Bucket, Key), + BinaryValue, + {{"Content-Type", "application/octet-stream"}}); + CHECK(Result.StatusCode == HttpResponseCode::Created); } { - cpr::Response Result = cpr::Get(cpr::Url{fmt::format("{}/{}/{}", UpstreamCfg.BaseUri, Bucket, Key)}, - cpr::Header{{"Accept", "application/octet-stream"}}); - CHECK(Result.status_code == 200); + HttpClient::Response Result = RemoteHttp.Get(fmt::format("/{}/{}", Bucket, Key), {{"Accept", "application/octet-stream"}}); + CHECK(Result.StatusCode == HttpResponseCode::OK); } { - cpr::Response Result = cpr::Get(cpr::Url{fmt::format("{}/{}/{}", LocalCfg.BaseUri, Bucket, Key)}, - cpr::Header{{"Accept", "application/octet-stream"}}); - CHECK(Result.status_code == 200); + HttpClient::Response Result = LocalHttp.Get(fmt::format("/{}/{}", Bucket, Key), {{"Accept", "application/octet-stream"}}); + CHECK(Result.StatusCode == HttpResponseCode::OK); } } - SUBCASE("query - 'local' does not query upstream (cppackage)") + SUBCASE("query - 'local' does not query upstream (cbpackage)") { ZenConfig UpstreamCfg = ZenConfig::New(TestEnv.GetNewPortNumber()); ZenServerInstance UpstreamInst(TestEnv); @@ -1109,30 +1087,31 @@ TEST_CASE("zcache.policy") zen::IoHash Key; zen::IoHash PayloadId; zen::CbPackage Package = GeneratePackage(Key, PayloadId); - auto Buf = ToBuffer(Package); + IoBuffer Buf = SerializeToBuffer(Package); + + HttpClient LocalHttp{LocalCfg.BaseUri}; + HttpClient RemoteHttp{UpstreamCfg.BaseUri}; // Store package upstream { - cpr::Response Result = cpr::Put(cpr::Url{fmt::format("{}/{}/{}", UpstreamCfg.BaseUri, Bucket, Key)}, - cpr::Body{(const char*)Buf.GetData(), Buf.GetSize()}, - cpr::Header{{"Content-Type", "application/x-ue-cbpkg"}}); - CHECK(Result.status_code == 201); + HttpClient::Response Result = RemoteHttp.Put(fmt::format("/{}/{}", Bucket, Key), Buf); + CHECK(Result.StatusCode == HttpResponseCode::Created); } { - cpr::Response Result = cpr::Get(cpr::Url{fmt::format("{}/{}/{}?Policy=QueryLocal,Store", LocalCfg.BaseUri, Bucket, Key)}, - cpr::Header{{"Accept", "application/x-ue-cbpkg"}}); - CHECK(Result.status_code == 404); + HttpClient::Response Result = + LocalHttp.Get(fmt::format("/{}/{}?Policy=QueryLocal,Store", Bucket, Key), {{"Accept", "application/x-ue-cbpkg"}}); + CHECK(Result.StatusCode == HttpResponseCode::NotFound); } { - cpr::Response Result = cpr::Get(cpr::Url{fmt::format("{}/{}/{}?Policy=Query,Store", LocalCfg.BaseUri, Bucket, Key)}, - cpr::Header{{"Accept", "application/x-ue-cbpkg"}}); - CHECK(Result.status_code == 200); + HttpClient::Response Result = + LocalHttp.Get(fmt::format("/{}/{}?Policy=Query,Store", Bucket, Key), {{"Accept", "application/x-ue-cbpkg"}}); + CHECK(Result.StatusCode == HttpResponseCode::OK); } } - SUBCASE("store - 'local' does not store upstream (cbpackge)") + SUBCASE("store - 'local' does not store upstream (cbpackage)") { ZenConfig UpstreamCfg = ZenConfig::New(TestEnv.GetNewPortNumber()); ZenServerInstance UpstreamInst(TestEnv); @@ -1147,26 +1126,25 @@ TEST_CASE("zcache.policy") zen::IoHash Key; zen::IoHash PayloadId; zen::CbPackage Package = GeneratePackage(Key, PayloadId); - auto Buf = ToBuffer(Package); + IoBuffer Buf = SerializeToBuffer(Package); - // Store packge locally + HttpClient LocalHttp{LocalCfg.BaseUri}; + HttpClient RemoteHttp{UpstreamCfg.BaseUri}; + + // Store package locally { - cpr::Response Result = cpr::Put(cpr::Url{fmt::format("{}/{}/{}?Policy=Query,StoreLocal", LocalCfg.BaseUri, Bucket, Key)}, - cpr::Body{(const char*)Buf.GetData(), Buf.GetSize()}, - cpr::Header{{"Content-Type", "application/x-ue-cbpkg"}}); - CHECK(Result.status_code == 201); + HttpClient::Response Result = LocalHttp.Put(fmt::format("/{}/{}?Policy=Query,StoreLocal", Bucket, Key), Buf); + CHECK(Result.StatusCode == HttpResponseCode::Created); } { - cpr::Response Result = cpr::Get(cpr::Url{fmt::format("{}/{}/{}", UpstreamCfg.BaseUri, Bucket, Key)}, - cpr::Header{{"Accept", "application/x-ue-cbpkg"}}); - CHECK(Result.status_code == 404); + HttpClient::Response Result = RemoteHttp.Get(fmt::format("/{}/{}", Bucket, Key), {{"Accept", "application/x-ue-cbpkg"}}); + CHECK(Result.StatusCode == HttpResponseCode::NotFound); } { - cpr::Response Result = cpr::Get(cpr::Url{fmt::format("{}/{}/{}", LocalCfg.BaseUri, Bucket, Key)}, - cpr::Header{{"Accept", "application/x-ue-cbpkg"}}); - CHECK(Result.status_code == 200); + HttpClient::Response Result = LocalHttp.Get(fmt::format("/{}/{}", Bucket, Key), {{"Accept", "application/x-ue-cbpkg"}}); + CHECK(Result.StatusCode == HttpResponseCode::OK); } } @@ -1185,26 +1163,25 @@ TEST_CASE("zcache.policy") zen::IoHash Key; zen::IoHash PayloadId; zen::CbPackage Package = GeneratePackage(Key, PayloadId); - auto Buf = ToBuffer(Package); + IoBuffer Buf = SerializeToBuffer(Package); + + HttpClient LocalHttp{LocalCfg.BaseUri}; + HttpClient RemoteHttp{UpstreamCfg.BaseUri}; // Store package locally and upstream { - cpr::Response Result = cpr::Put(cpr::Url{fmt::format("{}/{}/{}?Policy=Query,Store", LocalCfg.BaseUri, Bucket, Key)}, - cpr::Body{(const char*)Buf.GetData(), Buf.GetSize()}, - cpr::Header{{"Content-Type", "application/x-ue-cbpkg"}}); - CHECK(Result.status_code == 201); + HttpClient::Response Result = LocalHttp.Put(fmt::format("/{}/{}?Policy=Query,Store", Bucket, Key), Buf); + CHECK(Result.StatusCode == HttpResponseCode::Created); } { - cpr::Response Result = cpr::Get(cpr::Url{fmt::format("{}/{}/{}", UpstreamCfg.BaseUri, Bucket, Key)}, - cpr::Header{{"Accept", "application/x-ue-cbpkg"}}); - CHECK(Result.status_code == 200); + HttpClient::Response Result = RemoteHttp.Get(fmt::format("/{}/{}", Bucket, Key), {{"Accept", "application/x-ue-cbpkg"}}); + CHECK(Result.StatusCode == HttpResponseCode::OK); } { - cpr::Response Result = cpr::Get(cpr::Url{fmt::format("{}/{}/{}", LocalCfg.BaseUri, Bucket, Key)}, - cpr::Header{{"Accept", "application/x-ue-cbpkg"}}); - CHECK(Result.status_code == 200); + HttpClient::Response Result = LocalHttp.Get(fmt::format("/{}/{}", Bucket, Key), {{"Accept", "application/x-ue-cbpkg"}}); + CHECK(Result.StatusCode == HttpResponseCode::OK); } } @@ -1219,44 +1196,41 @@ TEST_CASE("zcache.policy") zen::IoHash Key; zen::IoHash PayloadId; zen::CbPackage Package = GeneratePackage(Key, PayloadId); - auto Buf = ToBuffer(Package); + IoBuffer Buf = SerializeToBuffer(Package); + + HttpClient Http{Cfg.BaseUri}; // Store package { - cpr::Response Result = cpr::Put(cpr::Url{fmt::format("{}/{}/{}", Cfg.BaseUri, Bucket, Key)}, - cpr::Body{(const char*)Buf.GetData(), Buf.GetSize()}, - cpr::Header{{"Content-Type", "application/x-ue-cbpkg"}}); - CHECK(Result.status_code == 201); + HttpClient::Response Result = Http.Put(fmt::format("/{}/{}", Bucket, Key), Buf); + CHECK(Result.StatusCode == HttpResponseCode::Created); } // Get package { - cpr::Response Result = cpr::Get(cpr::Url{fmt::format("{}/{}/{}?Policy=Default,SkipData", Cfg.BaseUri, Bucket, Key)}, - cpr::Header{{"Accept", "application/x-ue-cbpkg"}}); - CHECK(IsHttpSuccessCode(Result.status_code)); - IoBuffer Buffer(IoBuffer::Wrap, Result.text.c_str(), Result.text.size()); + HttpClient::Response Result = + Http.Get(fmt::format("/{}/{}?Policy=Default,SkipData", Bucket, Key), {{"Accept", "application/x-ue-cbpkg"}}); + CHECK(Result); CbPackage ResponsePackage; - CHECK(ResponsePackage.TryLoad(Buffer)); + CHECK(ResponsePackage.TryLoad(Result.ResponsePayload)); CHECK(ResponsePackage.GetAttachments().size() == 0); } // Get record { - cpr::Response Result = cpr::Get(cpr::Url{fmt::format("{}/{}/{}?Policy=Default,SkipData", Cfg.BaseUri, Bucket, Key)}, - cpr::Header{{"Accept", "application/x-ue-cb"}}); - CHECK(IsHttpSuccessCode(Result.status_code)); - IoBuffer Buffer(IoBuffer::Wrap, Result.text.c_str(), Result.text.size()); - CbObject ResponseObject = zen::LoadCompactBinaryObject(Buffer); - CHECK((bool)ResponseObject); + HttpClient::Response Result = + Http.Get(fmt::format("/{}/{}?Policy=Default,SkipData", Bucket, Key), {{"Accept", "application/x-ue-cb"}}); + CHECK(Result); + CbObject ResponseObject = zen::LoadCompactBinaryObject(Result.ResponsePayload); + CHECK(ResponseObject); } // Get payload { - cpr::Response Result = - cpr::Get(cpr::Url{fmt::format("{}/{}/{}/{}?Policy=Default,SkipData", Cfg.BaseUri, Bucket, Key, PayloadId)}, - cpr::Header{{"Accept", "application/x-ue-comp"}}); - CHECK(IsHttpSuccessCode(Result.status_code)); - CHECK(Result.text.size() == 0); + HttpClient::Response Result = + Http.Get(fmt::format("/{}/{}/{}?Policy=Default,SkipData", Bucket, Key, PayloadId), {{"Accept", "application/x-ue-comp"}}); + CHECK(Result); + CHECK(Result.ResponsePayload.GetSize() == 0); } } @@ -1269,22 +1243,22 @@ TEST_CASE("zcache.policy") const auto Bucket = "test"sv; zen::IoHash Key; - auto BinaryValue = GenerateData(1024, Key); + IoBuffer BinaryValue = GenerateData(1024, Key); + + HttpClient Http{Cfg.BaseUri}; // Store binary cache value { - cpr::Response Result = cpr::Put(cpr::Url{fmt::format("{}/{}/{}", Cfg.BaseUri, Bucket, Key)}, - cpr::Body{(const char*)BinaryValue.GetData(), BinaryValue.GetSize()}, - cpr::Header{{"Content-Type", "application/octet-stream"}}); - CHECK(Result.status_code == 201); + HttpClient::Response Result = Http.Put(fmt::format("/{}/{}", Bucket, Key), BinaryValue); + CHECK(Result.StatusCode == HttpResponseCode::Created); } // Get package { - cpr::Response Result = cpr::Get(cpr::Url{fmt::format("{}/{}/{}?Policy=Default,SkipData", Cfg.BaseUri, Bucket, Key)}, - cpr::Header{{"Accept", "application/octet-stream"}}); - CHECK(IsHttpSuccessCode(Result.status_code)); - CHECK(Result.text.size() == 0); + HttpClient::Response Result = + Http.Get(fmt::format("/{}/{}?Policy=Default,SkipData", Bucket, Key), {{"Accept", "application/octet-stream"}}); + CHECK(Result); + CHECK(Result.ResponsePayload.GetSize() == 0); } } } @@ -1323,6 +1297,8 @@ TEST_CASE("zcache.rpc") std::vector<CbPackage>* OutPackages = nullptr) -> std::vector<CacheKey> { std::vector<zen::CacheKey> OutKeys; + HttpClient Http{BaseUri}; + for (uint32_t Key = 1; Key <= Num; ++Key) { zen::IoHash KeyHash; @@ -1336,12 +1312,11 @@ TEST_CASE("zcache.rpc") CbPackage Package; CHECK(Request.Format(Package)); - IoBuffer Body = FormatPackageMessageBuffer(Package).Flatten().AsIoBuffer(); - cpr::Response Result = cpr::Post(cpr::Url{fmt::format("{}/$rpc", BaseUri)}, - cpr::Header{{"Content-Type", "application/x-ue-cbpkg"}, {"Accept", "application/x-ue-cbpkg"}}, - cpr::Body{(const char*)Body.GetData(), Body.GetSize()}); + IoBuffer Body = FormatPackageMessageBuffer(Package).Flatten().AsIoBuffer(); + Body.SetContentType(HttpContentType::kCbPackage); + HttpClient::Response Result = Http.Post("/$rpc", Body, {{"Accept", "application/x-ue-cbpkg"}}); - CHECK(Result.status_code == 200); + CHECK(Result.StatusCode == HttpResponseCode::OK); if (OutPackages) { OutPackages->emplace_back(std::move(Package)); @@ -1377,18 +1352,18 @@ TEST_CASE("zcache.rpc") CbObjectWriter RequestWriter; CHECK(Request.Format(RequestWriter)); - BinaryWriter Body; - RequestWriter.Save(Body); + IoBuffer Body = RequestWriter.Save().GetBuffer().AsIoBuffer(); + Body.SetContentType(HttpContentType::kCbObject); - cpr::Response Result = cpr::Post(cpr::Url{fmt::format("{}/$rpc", BaseUri)}, - cpr::Header{{"Content-Type", "application/x-ue-cb"}, {"Accept", "application/x-ue-cbpkg"}}, - cpr::Body{(const char*)Body.GetData(), Body.GetSize()}); + HttpClient Http{BaseUri}; + + HttpClient::Response Result = Http.Post("/$rpc", Body, {{"Accept", "application/x-ue-cbpkg"}}); GetCacheRecordResult OutResult; - if (Result.status_code == 200) + if (Result.StatusCode == HttpResponseCode::OK) { - CbPackage Response = ParsePackageMessage(zen::IoBuffer(zen::IoBuffer::Wrap, Result.text.data(), Result.text.size())); + CbPackage Response = ParsePackageMessage(Result.ResponsePayload); CHECK(!Response.IsNull()); OutResult.Response = std::move(Response); CHECK(OutResult.Result.Parse(OutResult.Response)); @@ -1542,6 +1517,9 @@ TEST_CASE("zcache.rpc") const size_t NumRecords = 4; std::vector<zen::CacheKey> Keys = PutCacheRecords(LocalCfg.BaseUri, Namespace, Bucket, NumRecords, PayloadSize); + HttpClient LocalHttp{LocalCfg.BaseUri}; + HttpClient UpstreamHttp{UpstreamCfg.BaseUri}; + for (const zen::CacheKey& CacheKey : Keys) { cacherequests::PutCacheRecordsRequest Request = {.AcceptMagic = kCbPkgMagic, .Namespace = std::string(Namespace)}; @@ -1550,14 +1528,13 @@ TEST_CASE("zcache.rpc") CbPackage Package; CHECK(Request.Format(Package)); - IoBuffer Body = FormatPackageMessageBuffer(Package).Flatten().AsIoBuffer(); - cpr::Response Result = cpr::Post(cpr::Url{fmt::format("{}/$rpc", LocalCfg.BaseUri)}, - cpr::Header{{"Content-Type", "application/x-ue-cbpkg"}, {"Accept", "application/x-ue-cbpkg"}}, - cpr::Body{(const char*)Body.GetData(), Body.GetSize()}); + IoBuffer Body = FormatPackageMessageBuffer(Package).Flatten().AsIoBuffer(); + Body.SetContentType(HttpContentType::kCbPackage); + HttpClient::Response Result = LocalHttp.Post("/$rpc", Body, {{"Accept", "application/x-ue-cbpkg"}}); - CHECK(Result.status_code == 200); + CHECK(Result.StatusCode == HttpResponseCode::OK); cacherequests::PutCacheRecordsResult ParsedResult; - CbPackage Response = ParsePackageMessage(zen::IoBuffer(zen::IoBuffer::Wrap, Result.text.data(), Result.text.size())); + CbPackage Response = ParsePackageMessage(Result.ResponsePayload); CHECK(!Response.IsNull()); CHECK(ParsedResult.Parse(Response)); for (bool ResponseSuccess : ParsedResult.Success) @@ -1610,6 +1587,9 @@ TEST_CASE("zcache.rpc") const size_t NumRecords = 4; std::vector<zen::CacheKey> Keys = PutCacheRecords(LocalCfg.BaseUri, Namespace, Bucket, NumRecords, PayloadSize); + HttpClient LocalHttp{LocalCfg.BaseUri}; + HttpClient UpstreamHttp{UpstreamCfg.BaseUri}; + for (const zen::CacheKey& CacheKey : Keys) { cacherequests::PutCacheRecordsRequest Request = {.AcceptMagic = kCbPkgMagic, .Namespace = std::string(Namespace)}; @@ -1618,14 +1598,14 @@ TEST_CASE("zcache.rpc") CbPackage Package; CHECK(Request.Format(Package)); - IoBuffer Body = FormatPackageMessageBuffer(Package).Flatten().AsIoBuffer(); - cpr::Response Result = cpr::Post(cpr::Url{fmt::format("{}/$rpc", LocalCfg.BaseUri)}, - cpr::Header{{"Content-Type", "application/x-ue-cbpkg"}, {"Accept", "application/x-ue-cbpkg"}}, - cpr::Body{(const char*)Body.GetData(), Body.GetSize()}); + IoBuffer Body = FormatPackageMessageBuffer(Package).Flatten().AsIoBuffer(); + Body.SetContentType(HttpContentType::kCbPackage); + + HttpClient::Response Result = LocalHttp.Post("/$rpc", Body, {{"Accept", "application/x-ue-cbpkg"}}); - CHECK(Result.status_code == 200); + CHECK(Result.StatusCode == HttpResponseCode::OK); cacherequests::PutCacheRecordsResult ParsedResult; - CbPackage Response = ParsePackageMessage(zen::IoBuffer(zen::IoBuffer::Wrap, Result.text.data(), Result.text.size())); + CbPackage Response = ParsePackageMessage(Result.ResponsePayload); CHECK(!Response.IsNull()); CHECK(ParsedResult.Parse(Response)); CHECK(Request.Requests.size() == ParsedResult.Success.size()); @@ -1680,6 +1660,9 @@ TEST_CASE("zcache.rpc") ZenServerInstance LocalServer(TestEnv); SpawnServer(LocalServer, LocalCfg); + HttpClient LocalHttp{LocalCfg.BaseUri}; + HttpClient UpstreamHttp{UpstreamCfg.BaseUri}; + size_t PayloadSize = 1024; std::string_view Namespace("ue4.ddc"sv); std::string_view Bucket("mastodon"sv); @@ -1694,14 +1677,13 @@ TEST_CASE("zcache.rpc") CbPackage Package; CHECK(Request.Format(Package)); - IoBuffer Body = FormatPackageMessageBuffer(Package).Flatten().AsIoBuffer(); - cpr::Response Result = cpr::Post(cpr::Url{fmt::format("{}/$rpc", LocalCfg.BaseUri)}, - cpr::Header{{"Content-Type", "application/x-ue-cbpkg"}, {"Accept", "application/x-ue-cbpkg"}}, - cpr::Body{(const char*)Body.GetData(), Body.GetSize()}); + IoBuffer Body = FormatPackageMessageBuffer(Package).Flatten().AsIoBuffer(); + Body.SetContentType(HttpContentType::kCbPackage); + HttpClient::Response Result = LocalHttp.Post("/$rpc", Body, {{"Accept", "application/x-ue-cbpkg"}}); - CHECK(Result.status_code == 200); + CHECK(Result.StatusCode == HttpResponseCode::OK); cacherequests::PutCacheRecordsResult ParsedResult; - CbPackage Response = ParsePackageMessage(zen::IoBuffer(zen::IoBuffer::Wrap, Result.text.data(), Result.text.size())); + CbPackage Response = ParsePackageMessage(Result.ResponsePayload); CHECK(!Response.IsNull()); CHECK(ParsedResult.Parse(Response)); for (bool ResponseSuccess : ParsedResult.Success) @@ -1748,6 +1730,9 @@ TEST_CASE("zcache.rpc") ZenServerInstance LocalServer(TestEnv); SpawnServer(LocalServer, LocalCfg); + HttpClient LocalHttp{LocalCfg.BaseUri}; + HttpClient UpstreamHttp{UpstreamCfg.BaseUri}; + size_t PayloadSize = 1024; std::string_view Namespace("ue4.ddc"sv); std::string_view Bucket("mastodon"sv); @@ -1758,14 +1743,13 @@ TEST_CASE("zcache.rpc") for (const CbPackage& Package : Packages) { - IoBuffer Body = FormatPackageMessageBuffer(Package).Flatten().AsIoBuffer(); - cpr::Response Result = cpr::Post(cpr::Url{fmt::format("{}/$rpc", LocalCfg.BaseUri)}, - cpr::Header{{"Content-Type", "application/x-ue-cbpkg"}, {"Accept", "application/x-ue-cbpkg"}}, - cpr::Body{(const char*)Body.GetData(), Body.GetSize()}); + IoBuffer Body = FormatPackageMessageBuffer(Package).Flatten().AsIoBuffer(); + Body.SetContentType(HttpContentType::kCbPackage); + HttpClient::Response Result = LocalHttp.Post("/$rpc", Body, {{"Accept", "application/x-ue-cbpkg"}}); - CHECK(Result.status_code == 200); + CHECK(Result.StatusCode == HttpResponseCode::OK); cacherequests::PutCacheRecordsResult ParsedResult; - CbPackage Response = ParsePackageMessage(zen::IoBuffer(zen::IoBuffer::Wrap, Result.text.data(), Result.text.size())); + CbPackage Response = ParsePackageMessage(Result.ResponsePayload); CHECK(!Response.IsNull()); CHECK(ParsedResult.Parse(Response)); for (bool ResponseSuccess : ParsedResult.Success) @@ -2082,14 +2066,14 @@ TEST_CASE("zcache.failing.upstream") CbPackage Package; CHECK(Request.Format(Package)); - IoBuffer Body = FormatPackageMessageBuffer(Package).Flatten().AsIoBuffer(); - cpr::Response Result = cpr::Post(cpr::Url{fmt::format("{}/$rpc", BaseUri)}, - cpr::Header{{"Content-Type", "application/x-ue-cbpkg"}, {"Accept", "application/x-ue-cbpkg"}}, - cpr::Body{(const char*)Body.GetData(), Body.GetSize()}); + HttpClient Http{BaseUri}; + + IoBuffer Body = FormatPackageMessageBuffer(Package).Flatten().AsIoBuffer(); + HttpClient::Response Result = Http.Post("/$rpc", Body, {{"Accept", "application/x-ue-cbpkg"}}); - if (Result.status_code != 200) + if (Result.StatusCode != HttpResponseCode::OK) { - ZEN_DEBUG("PutCacheRecords failed with {}, reason '{}'", Result.status_code, Result.reason); + ZEN_DEBUG("PutCacheRecords failed with {}, reason '{}'", ToString(Result.StatusCode), Result.ErrorMessage("")); OutKeys.clear(); } @@ -2118,18 +2102,18 @@ TEST_CASE("zcache.failing.upstream") CbObjectWriter RequestWriter; CHECK(Request.Format(RequestWriter)); - BinaryWriter Body; - RequestWriter.Save(Body); + IoBuffer Body = RequestWriter.Save().GetBuffer().AsIoBuffer(); + Body.SetContentType(HttpContentType::kCbObject); - cpr::Response Result = cpr::Post(cpr::Url{fmt::format("{}/$rpc", BaseUri)}, - cpr::Header{{"Content-Type", "application/x-ue-cb"}, {"Accept", "application/x-ue-cbpkg"}}, - cpr::Body{(const char*)Body.GetData(), Body.GetSize()}); + HttpClient Http{BaseUri}; + + HttpClient::Response Result = Http.Post("/$rpc", Body, {{"Accept", "application/x-ue-cbpkg"}}); GetCacheRecordResult OutResult; - if (Result.status_code == 200) + if (Result.StatusCode == HttpResponseCode::OK) { - CbPackage Response = ParsePackageMessage(zen::IoBuffer(zen::IoBuffer::Wrap, Result.text.data(), Result.text.size())); + CbPackage Response = ParsePackageMessage(Result.ResponsePayload); if (!Response.IsNull()) { OutResult.Response = std::move(Response); @@ -2139,7 +2123,7 @@ TEST_CASE("zcache.failing.upstream") } else { - ZEN_DEBUG("GetCacheRecords with {}, reason '{}'", Result.reason, Result.status_code); + ZEN_DEBUG("GetCacheRecords with {}, reason '{}'", ToString(Result.StatusCode), Result.ErrorMessage("")); } return OutResult; @@ -2339,14 +2323,16 @@ TEST_CASE("zcache.rpc.partialchunks") CbPackage Package; CHECK(Request.Format(Package)); - IoBuffer Body = FormatPackageMessageBuffer(Package).Flatten().AsIoBuffer(); - cpr::Response Result = cpr::Post(cpr::Url{fmt::format("{}/$rpc", BaseUri)}, - cpr::Header{{"Content-Type", "application/x-ue-cbpkg"}, {"Accept", "application/x-ue-cbpkg"}}, - cpr::Body{(const char*)Body.GetData(), Body.GetSize()}); + HttpClient Http{BaseUri}; + + IoBuffer Body = FormatPackageMessageBuffer(Package).Flatten().AsIoBuffer(); + Body.SetContentType(HttpContentType::kCbPackage); - if (Result.status_code != 200) + HttpClient::Response Result = Http.Post("/$rpc", Body, {{"Accept", "application/x-ue-cbpkg"}}); + + if (Result.StatusCode != HttpResponseCode::OK) { - ZEN_DEBUG("PutCacheRecords failed with {}, reason '{}'", Result.status_code, Result.reason); + ZEN_DEBUG("PutCacheRecords failed with {}, reason '{}'", ToString(Result.StatusCode), Result.ErrorMessage("")); Keys.clear(); } @@ -2379,14 +2365,16 @@ TEST_CASE("zcache.rpc.partialchunks") .Requests = {{.Key = Key, .ValueId = ValueId, .RawOffset = Options.Offset, .RawSize = Options.Size}}}; CbPackage Package; CHECK(Request.Format(Package)); - IoBuffer Body = FormatPackageMessageBuffer(Package).Flatten().AsIoBuffer(); - cpr::Response Result = cpr::Post(cpr::Url{fmt::format("{}/$rpc", BaseUri)}, - cpr::Header{{"Content-Type", "application/x-ue-cbpkg"}, {"Accept", "application/x-ue-cbpkg"}}, - cpr::Body{(const char*)Body.GetData(), Body.GetSize()}); + IoBuffer Body = FormatPackageMessageBuffer(Package).Flatten().AsIoBuffer(); + Body.SetContentType(HttpContentType::kCbPackage); + + HttpClient Http{BaseUri}; - CHECK(Result.status_code == 200); + HttpClient::Response Result = Http.Post("/$rpc", Body, {{"Accept", "application/x-ue-cbpkg"}}); - CbPackage Response = ParsePackageMessage(zen::IoBuffer(zen::IoBuffer::Wrap, Result.text.data(), Result.text.size())); + CHECK(Result.StatusCode == HttpResponseCode::OK); + + CbPackage Response = ParsePackageMessage(Result.ResponsePayload); bool Loaded = !Response.IsNull(); CHECK_MESSAGE(Loaded, "GetCacheChunks response failed to load."); cacherequests::GetCacheChunksResult GetCacheChunksResult; @@ -2481,6 +2469,14 @@ TEST_CASE("zcache.rpc.partialchunks") RpcAcceptOptions::kAllowPartialCacheChunks}); } +IoBuffer +FormatPackageBody(const CbPackage& Package) +{ + IoBuffer Body = FormatPackageMessageBuffer(Package).Flatten().AsIoBuffer(); + Body.SetContentType(HttpContentType::kCbPackage); + return Body; +} + TEST_CASE("zcache.rpc.allpolicies") { using namespace std::literals; @@ -2495,6 +2491,7 @@ TEST_CASE("zcache.rpc.allpolicies") SpawnServer(LocalServer, LocalCfg); const auto BaseUri = fmt::format("http://localhost:{}/z$", LocalServer.GetBasePort()); + HttpClient Http{BaseUri}; std::string_view TestVersion = "F72150A02AE34B57A9EC91D36BA1CE08"sv; std::string_view TestBucket = "allpoliciestest"sv; @@ -2711,11 +2708,9 @@ TEST_CASE("zcache.rpc.allpolicies") CbPackage Package; CHECK(Request.Format(Package)); - IoBuffer Body = FormatPackageMessageBuffer(Package).Flatten().AsIoBuffer(); - cpr::Response Result = cpr::Post(cpr::Url{fmt::format("{}/$rpc", BaseUri)}, - cpr::Header{{"Content-Type", "application/x-ue-cbpkg"}, {"Accept", "application/x-ue-cbpkg"}}, - cpr::Body{(const char*)Body.GetData(), Body.GetSize()}); - CHECK_MESSAGE(Result.status_code == 200, "PutCacheRecords unexpectedly failed."); + IoBuffer Body = FormatPackageBody(Package); + HttpClient::Response Result = Http.Post("/$rpc", Body, {{"Accept", "application/x-ue-cbpkg"}}); + CHECK_MESSAGE(Result.StatusCode == HttpResponseCode::OK, "PutCacheRecords unexpectedly failed."); } // PutCacheValues @@ -2735,11 +2730,9 @@ TEST_CASE("zcache.rpc.allpolicies") CbPackage Package; CHECK(Request.Format(Package)); - IoBuffer Body = FormatPackageMessageBuffer(Package).Flatten().AsIoBuffer(); - cpr::Response Result = cpr::Post(cpr::Url{fmt::format("{}/$rpc", BaseUri)}, - cpr::Header{{"Content-Type", "application/x-ue-cbpkg"}, {"Accept", "application/x-ue-cbpkg"}}, - cpr::Body{(const char*)Body.GetData(), Body.GetSize()}); - CHECK_MESSAGE(Result.status_code == 200, "PutCacheValues unexpectedly failed."); + IoBuffer Body = FormatPackageBody(Package); + HttpClient::Response Result = Http.Post("/$rpc", Body, {{"Accept", "application/x-ue-cbpkg"}}); + CHECK_MESSAGE(Result.StatusCode == HttpResponseCode::OK, "PutCacheValues unexpectedly failed."); } for (KeyData& KeyData : KeyDatas) @@ -2772,12 +2765,10 @@ TEST_CASE("zcache.rpc.allpolicies") CbPackage Package; CHECK(Request.Format(Package)); - IoBuffer Body = FormatPackageMessageBuffer(Package).Flatten().AsIoBuffer(); - cpr::Response Result = cpr::Post(cpr::Url{fmt::format("{}/$rpc", BaseUri)}, - cpr::Header{{"Content-Type", "application/x-ue-cbpkg"}, {"Accept", "application/x-ue-cbpkg"}}, - cpr::Body{(const char*)Body.GetData(), Body.GetSize()}); - CHECK_MESSAGE(Result.status_code == 200, "GetCacheRecords unexpectedly failed."); - CbPackage Response = ParsePackageMessage(zen::IoBuffer(zen::IoBuffer::Wrap, Result.text.data(), Result.text.size())); + IoBuffer Body = FormatPackageBody(Package); + HttpClient::Response Result = Http.Post("/$rpc", Body, {{"Accept", "application/x-ue-cbpkg"}}); + CHECK_MESSAGE(Result.StatusCode == HttpResponseCode::OK, "GetCacheRecords unexpectedly failed."); + CbPackage Response = ParsePackageMessage(Result.ResponsePayload); bool Loaded = !Response.IsNull(); CHECK_MESSAGE(Loaded, "GetCacheRecords response failed to load."); cacherequests::GetCacheRecordsResult RequestResult; @@ -2852,12 +2843,10 @@ TEST_CASE("zcache.rpc.allpolicies") CbPackage Package; CHECK(GetCacheValuesRequest.Format(Package)); - IoBuffer Body = FormatPackageMessageBuffer(Package).Flatten().AsIoBuffer(); - cpr::Response Result = cpr::Post(cpr::Url{fmt::format("{}/$rpc", BaseUri)}, - cpr::Header{{"Content-Type", "application/x-ue-cbpkg"}, {"Accept", "application/x-ue-cbpkg"}}, - cpr::Body{(const char*)Body.GetData(), Body.GetSize()}); - CHECK_MESSAGE(Result.status_code == 200, "GetCacheValues unexpectedly failed."); - IoBuffer MessageBuffer(zen::IoBuffer::Wrap, Result.text.data(), Result.text.size()); + IoBuffer Body = FormatPackageBody(Package); + HttpClient::Response Result = Http.Post("/$rpc", Body, {{"Accept", "application/x-ue-cbpkg"}}); + CHECK_MESSAGE(Result.StatusCode == HttpResponseCode::OK, "GetCacheValues unexpectedly failed."); + IoBuffer MessageBuffer(Result.ResponsePayload); CbPackage Response = ParsePackageMessage(MessageBuffer); bool Loaded = !Response.IsNull(); CHECK_MESSAGE(Loaded, "GetCacheValues response failed to load."); @@ -2922,12 +2911,10 @@ TEST_CASE("zcache.rpc.allpolicies") CbPackage Package; CHECK(GetCacheChunksRequest.Format(Package)); - IoBuffer Body = FormatPackageMessageBuffer(Package).Flatten().AsIoBuffer(); - cpr::Response Result = cpr::Post(cpr::Url{fmt::format("{}/$rpc", BaseUri)}, - cpr::Header{{"Content-Type", "application/x-ue-cbpkg"}, {"Accept", "application/x-ue-cbpkg"}}, - cpr::Body{(const char*)Body.GetData(), Body.GetSize()}); - CHECK_MESSAGE(Result.status_code == 200, "GetCacheChunks unexpectedly failed."); - CbPackage Response = ParsePackageMessage(zen::IoBuffer(zen::IoBuffer::Wrap, Result.text.data(), Result.text.size())); + IoBuffer Body = FormatPackageBody(Package); + HttpClient::Response Result = Http.Post("/$rpc", Body, {{"Accept", "application/x-ue-cbpkg"}}); + CHECK_MESSAGE(Result.StatusCode == HttpResponseCode::OK, "GetCacheChunks unexpectedly failed."); + CbPackage Response = ParsePackageMessage(Result.ResponsePayload); bool Loaded = !Response.IsNull(); CHECK_MESSAGE(Loaded, "GetCacheChunks response failed to load."); cacherequests::GetCacheChunksResult GetCacheChunksResult; @@ -3058,20 +3045,23 @@ TEST_CASE("http.basics") ZenServerInstance& Instance = Servers.GetInstance(0); const std::string BaseUri = Instance.GetBaseUri(); + HttpClient Http{BaseUri}; + { - cpr::Response r = cpr::Get(cpr::Url{fmt::format("{}/testing/hello", BaseUri)}); - CHECK(IsHttpSuccessCode(r.status_code)); + HttpClient::Response r = Http.Get("/testing/hello"); + CHECK(r); } { - cpr::Response r = cpr::Post(cpr::Url{fmt::format("{}/testing/hello", BaseUri)}); - CHECK_EQ(r.status_code, 404); + HttpClient::Response r = Http.Post("/testing/hello"); + CHECK_EQ(r.StatusCode, HttpResponseCode::NotFound); } { - cpr::Response r = cpr::Post(cpr::Url{fmt::format("{}/testing/echo", BaseUri)}, cpr::Body{"yoyoyoyo"}); - CHECK_EQ(r.status_code, 200); - CHECK_EQ(r.text, "yoyoyoyo"); + IoBuffer Body{IoBuffer::Wrap, "yoyoyoyo", 8}; + HttpClient::Response r = Http.Post("/testing/echo", Body); + CHECK_EQ(r.StatusCode, HttpResponseCode::OK); + CHECK(r.ResponsePayload.GetView().EqualBytes(Body.GetView())); } } @@ -3178,12 +3168,6 @@ CreateOplogOp(const Oid& Id, const std::span<const std::pair<Oid, CompressedBuff return Object.Save(); }; -cpr::Body -AsBody(const IoBuffer& Payload) -{ - return cpr::Body{(const char*)Payload.GetData(), Payload.Size()}; -}; - enum CbWriterMeta { BeginObject, @@ -3286,46 +3270,40 @@ TEST_CASE("project.remote") Ops.insert({Id, OpCoreHash}); }; - auto MakeProject = [](cpr::Session& Session, std::string_view UrlBase, std::string_view ProjectName) { + auto MakeProject = [](std::string_view UrlBase, std::string_view ProjectName) { CbObjectWriter Project; Project.AddString("id"sv, ProjectName); Project.AddString("root"sv, ""sv); Project.AddString("engine"sv, ""sv); Project.AddString("project"sv, ""sv); Project.AddString("projectfile"sv, ""sv); - IoBuffer ProjectPayload = Project.Save().GetBuffer().AsIoBuffer(); - std::string ProjectRequest = fmt::format("{}/prj/{}", UrlBase, ProjectName); - Session.SetUrl({ProjectRequest}); - Session.SetBody(cpr::Body{(const char*)ProjectPayload.GetData(), ProjectPayload.GetSize()}); - cpr::Response Response = Session.Post(); - CHECK(IsHttpSuccessCode(Response.status_code)); + IoBuffer ProjectPayload = Project.Save().GetBuffer().AsIoBuffer(); + ProjectPayload.SetContentType(HttpContentType::kCbObject); + + HttpClient Http{UrlBase}; + HttpClient::Response Response = Http.Post(fmt::format("/prj/{}", ProjectName), ProjectPayload); + CHECK(Response); }; - auto MakeOplog = [](cpr::Session& Session, std::string_view UrlBase, std::string_view ProjectName, std::string_view OplogName) { - std::string CreateOplogRequest = fmt::format("{}/prj/{}/oplog/{}", UrlBase, ProjectName, OplogName); - Session.SetUrl({CreateOplogRequest}); - Session.SetBody(cpr::Body{}); - cpr::Response Response = Session.Post(); - CHECK(IsHttpSuccessCode(Response.status_code)); + auto MakeOplog = [](std::string_view UrlBase, std::string_view ProjectName, std::string_view OplogName) { + HttpClient Http{UrlBase}; + HttpClient::Response Response = Http.Post(fmt::format("/prj/{}/oplog/{}", ProjectName, OplogName), IoBuffer{}); + CHECK(Response); }; - auto MakeOp = [](cpr::Session& Session, - std::string_view UrlBase, - std::string_view ProjectName, - std::string_view OplogName, - const CbPackage& OpPackage) { - std::string CreateOpRequest = fmt::format("{}/prj/{}/oplog/{}/new", UrlBase, ProjectName, OplogName); - Session.SetUrl({CreateOpRequest}); + auto MakeOp = [](std::string_view UrlBase, std::string_view ProjectName, std::string_view OplogName, const CbPackage& OpPackage) { zen::BinaryWriter MemOut; legacy::SaveCbPackage(OpPackage, MemOut); - Session.SetBody(cpr::Body{(const char*)MemOut.Data(), MemOut.Size()}); - cpr::Response Response = Session.Post(); - CHECK(IsHttpSuccessCode(Response.status_code)); + IoBuffer Body{IoBuffer::Wrap, MemOut.GetData(), MemOut.GetSize()}; + Body.SetContentType(HttpContentType::kCbPackage); + + HttpClient Http{UrlBase}; + HttpClient::Response Response = Http.Post(fmt::format("/prj/{}/oplog/{}/new", ProjectName, OplogName), Body); + CHECK(Response); }; - cpr::Session Session; - MakeProject(Session, Servers.GetInstance(0).GetBaseUri(), "proj0"); - MakeOplog(Session, Servers.GetInstance(0).GetBaseUri(), "proj0", "oplog0"); + MakeProject(Servers.GetInstance(0).GetBaseUri(), "proj0"); + MakeOplog(Servers.GetInstance(0).GetBaseUri(), "proj0", "oplog0"); std::unordered_map<Oid, uint32_t, Oid::Hasher> SourceOps; for (const Oid& OpId : OpIds) @@ -3333,7 +3311,7 @@ TEST_CASE("project.remote") CbPackage OpPackage = CreateOplogPackage(OpId, Attachments[OpId]); CHECK(OpPackage.GetAttachments().size() == Attachments[OpId].size()); AddOp(OpPackage.GetObject(), SourceOps); - MakeOp(Session, Servers.GetInstance(0).GetBaseUri(), "proj0", "oplog0", OpPackage); + MakeOp(Servers.GetInstance(0).GetBaseUri(), "proj0", "oplog0", OpPackage); } std::vector<IoHash> AttachmentHashes; @@ -3351,47 +3329,45 @@ TEST_CASE("project.remote") Write(Writer); IoBuffer Result = Writer.Save().GetBuffer().AsIoBuffer(); Result.MakeOwned(); + Result.SetContentType(HttpContentType::kCbObject); return Result; }; - auto ValidateAttachments = [&MakeCbObjectPayload, &AttachmentHashes, &Servers, &Session](int ServerIndex, - std::string_view Project, - std::string_view Oplog) { - std::string GetChunksRequest = fmt::format("{}/prj/{}/oplog/{}/rpc", Servers.GetInstance(ServerIndex).GetBaseUri(), Project, Oplog); - Session.SetUrl({GetChunksRequest}); - IoBuffer Payload = MakeCbObjectPayload([&AttachmentHashes](CbObjectWriter& Writer) { - Writer << "method"sv - << "getchunks"sv; - Writer << "chunks"sv << BeginArray; - for (const IoHash& Chunk : AttachmentHashes) + auto ValidateAttachments = + [&MakeCbObjectPayload, &AttachmentHashes, &Servers](int ServerIndex, std::string_view Project, std::string_view Oplog) { + HttpClient Http{Servers.GetInstance(ServerIndex).GetBaseUri()}; + + IoBuffer Payload = MakeCbObjectPayload([&AttachmentHashes](CbObjectWriter& Writer) { + Writer << "method"sv + << "getchunks"sv; + Writer << "chunks"sv << BeginArray; + for (const IoHash& Chunk : AttachmentHashes) + { + Writer << Chunk; + } + Writer << EndArray; // chunks + }); + + HttpClient::Response Response = + Http.Post(fmt::format("/prj/{}/oplog/{}/rpc", Project, Oplog), Payload, {{"Accept", "application/x-ue-cbpkg"}}); + CHECK(Response); + CbPackage ResponsePackage = ParsePackageMessage(Response.ResponsePayload); + CHECK(ResponsePackage.GetAttachments().size() == AttachmentHashes.size()); + for (auto A : ResponsePackage.GetAttachments()) { - Writer << Chunk; + CHECK(IoHash::HashBuffer(A.AsCompressedBinary().DecompressToComposite()) == A.GetHash()); } - Writer << EndArray; // chunks - }); - Session.SetBody(AsBody(Payload)); - Session.SetHeader(cpr::Header{{"Content-Type", "application/x-ue-cb"}, {"Accept", "application/x-ue-cbpkg"}}); - cpr::Response Response = Session.Post(); - CHECK(IsHttpSuccessCode(Response.status_code)); - CbPackage ResponsePackage = ParsePackageMessage(IoBuffer(IoBuffer::Wrap, Response.text.data(), Response.text.size())); - CHECK(ResponsePackage.GetAttachments().size() == AttachmentHashes.size()); - for (auto A : ResponsePackage.GetAttachments()) - { - CHECK(IoHash::HashBuffer(A.AsCompressedBinary().DecompressToComposite()) == A.GetHash()); - } - }; + }; - auto ValidateOplog = [&SourceOps, &AddOp, &Servers, &Session](int ServerIndex, std::string_view Project, std::string_view Oplog) { + auto ValidateOplog = [&SourceOps, &AddOp, &Servers](int ServerIndex, std::string_view Project, std::string_view Oplog) { std::unordered_map<Oid, uint32_t, Oid::Hasher> TargetOps; std::vector<CbObject> ResultingOplog; - std::string GetOpsRequest = - fmt::format("{}/prj/{}/oplog/{}/entries", Servers.GetInstance(ServerIndex).GetBaseUri(), Project, Oplog); - Session.SetUrl({GetOpsRequest}); - cpr::Response Response = Session.Get(); - CHECK(IsHttpSuccessCode(Response.status_code)); + HttpClient Http{Servers.GetInstance(ServerIndex).GetBaseUri()}; + HttpClient::Response Response = Http.Get(fmt::format("/prj/{}/oplog/{}/entries", Project, Oplog)); + CHECK(Response); - IoBuffer Payload(IoBuffer::Wrap, Response.text.data(), Response.text.size()); + IoBuffer Payload(Response.ResponsePayload); CbObject OplogResonse = LoadCompactBinaryObject(Payload); CbArrayView EntriesArray = OplogResonse["entries"sv].AsArrayView(); @@ -3408,19 +3384,20 @@ TEST_CASE("project.remote") CHECK(SourceOps == TargetOps); }; - auto WaitForCompletion = [&Session](ZenServerInstance& Server, const cpr::Response& Response) { - CHECK(IsHttpSuccessCode(Response.status_code)); - uint64_t JobId = ParseInt<uint64_t>(Response.text).value_or(0); + auto HttpWaitForCompletion = [](ZenServerInstance& Server, const HttpClient::Response& Response) { + REQUIRE(Response); + const uint64_t JobId = ParseInt<uint64_t>(Response.AsText()).value_or(0); CHECK(JobId != 0); - Session.SetUrl(fmt::format("{}/admin/jobs/{}", Server.GetBaseUri(), JobId)); - Session.SetHeader(cpr::Header{{"Accept", std::string(ToString(ZenContentType::kCbObject))}}); + + HttpClient Http{Server.GetBaseUri()}; + while (true) { - cpr::Response StatusResponse = Session.Get(); - CHECK(IsHttpSuccessCode(StatusResponse.status_code)); - CbObject ResponseObject = - LoadCompactBinaryObject(IoBuffer(IoBuffer::Wrap, StatusResponse.text.data(), StatusResponse.text.size())); - std::string_view Status = ResponseObject["Status"sv].AsString(); + HttpClient::Response StatusResponse = + Http.Get(fmt::format("/admin/jobs/{}", JobId), {{"Accept", ToString(ZenContentType::kCbObject)}}); + CHECK(StatusResponse); + CbObject ResponseObject = StatusResponse.AsObject(); + std::string_view Status = ResponseObject["Status"sv].AsString(); CHECK(Status != "Aborted"sv); if (Status == "Complete"sv) { @@ -3434,9 +3411,6 @@ TEST_CASE("project.remote") { ScopedTemporaryDirectory TempDir; { - std::string SaveOplogRequest = fmt::format("{}/prj/{}/oplog/{}/rpc", Servers.GetInstance(0).GetBaseUri(), "proj0", "oplog0"); - Session.SetUrl({SaveOplogRequest}); - IoBuffer Payload = MakeCbObjectPayload([&AttachmentHashes, path = TempDir.Path().string()](CbObjectWriter& Writer) { Writer << "method"sv << "export"sv; @@ -3456,17 +3430,15 @@ TEST_CASE("project.remote") } Writer << EndObject; // "params" }); - Session.SetBody(AsBody(Payload)); - Session.SetHeader(cpr::Header{{"Content-Type", "application/x-ue-cb"}}); - cpr::Response Response = Session.Post(); - WaitForCompletion(Servers.GetInstance(0), Response); + + HttpClient Http{Servers.GetInstance(0).GetBaseUri()}; + + HttpClient::Response Response = Http.Post(fmt::format("/prj/{}/oplog/{}/rpc", "proj0", "oplog0"), Payload); + HttpWaitForCompletion(Servers.GetInstance(0), Response); } { - MakeProject(Session, Servers.GetInstance(1).GetBaseUri(), "proj0_copy"); - MakeOplog(Session, Servers.GetInstance(1).GetBaseUri(), "proj0_copy", "oplog0_copy"); - std::string LoadOplogRequest = - fmt::format("{}/prj/{}/oplog/{}/rpc", Servers.GetInstance(1).GetBaseUri(), "proj0_copy", "oplog0_copy"); - Session.SetUrl({LoadOplogRequest}); + MakeProject(Servers.GetInstance(1).GetBaseUri(), "proj0_copy"); + MakeOplog(Servers.GetInstance(1).GetBaseUri(), "proj0_copy", "oplog0_copy"); IoBuffer Payload = MakeCbObjectPayload([&AttachmentHashes, path = TempDir.Path().string()](CbObjectWriter& Writer) { Writer << "method"sv @@ -3484,11 +3456,11 @@ TEST_CASE("project.remote") } Writer << EndObject; // "params" }); - Session.SetBody(AsBody(Payload)); - Session.SetHeader(cpr::Header{{"Content-Type", "application/x-ue-cb"}}); - cpr::Response Response = Session.Post(); - WaitForCompletion(Servers.GetInstance(1), Response); + HttpClient Http{Servers.GetInstance(1).GetBaseUri()}; + + HttpClient::Response Response = Http.Post(fmt::format("/prj/{}/oplog/{}/rpc", "proj0_copy", "oplog0_copy"), Payload); + HttpWaitForCompletion(Servers.GetInstance(1), Response); } ValidateAttachments(1, "proj0_copy", "oplog0_copy"); ValidateOplog(1, "proj0_copy", "oplog0_copy"); @@ -3498,9 +3470,6 @@ TEST_CASE("project.remote") { ScopedTemporaryDirectory TempDir; { - std::string SaveOplogRequest = fmt::format("{}/prj/{}/oplog/{}/rpc", Servers.GetInstance(0).GetBaseUri(), "proj0", "oplog0"); - Session.SetUrl({SaveOplogRequest}); - IoBuffer Payload = MakeCbObjectPayload([&](CbObjectWriter& Writer) { Writer << "method"sv << "export"sv; @@ -3521,17 +3490,15 @@ TEST_CASE("project.remote") } Writer << EndObject; // "params" }); - Session.SetBody(AsBody(Payload)); - Session.SetHeader(cpr::Header{{"Content-Type", "application/x-ue-cb"}}); - cpr::Response Response = Session.Post(); - WaitForCompletion(Servers.GetInstance(0), Response); + + HttpClient Http{Servers.GetInstance(0).GetBaseUri()}; + + HttpClient::Response Response = Http.Post(fmt::format("/prj/{}/oplog/{}/rpc", "proj0", "oplog0"), Payload); + HttpWaitForCompletion(Servers.GetInstance(0), Response); } { - MakeProject(Session, Servers.GetInstance(1).GetBaseUri(), "proj0_copy"); - MakeOplog(Session, Servers.GetInstance(1).GetBaseUri(), "proj0_copy", "oplog0_copy"); - std::string LoadOplogRequest = - fmt::format("{}/prj/{}/oplog/{}/rpc", Servers.GetInstance(1).GetBaseUri(), "proj0_copy", "oplog0_copy"); - Session.SetUrl({LoadOplogRequest}); + MakeProject(Servers.GetInstance(1).GetBaseUri(), "proj0_copy"); + MakeOplog(Servers.GetInstance(1).GetBaseUri(), "proj0_copy", "oplog0_copy"); IoBuffer Payload = MakeCbObjectPayload([&](CbObjectWriter& Writer) { Writer << "method"sv << "import"sv; @@ -3548,10 +3515,11 @@ TEST_CASE("project.remote") } Writer << EndObject; // "params" }); - Session.SetBody(AsBody(Payload)); - Session.SetHeader(cpr::Header{{"Content-Type", "application/x-ue-cb"}}); - cpr::Response Response = Session.Post(); - WaitForCompletion(Servers.GetInstance(1), Response); + + HttpClient Http{Servers.GetInstance(1).GetBaseUri()}; + + HttpClient::Response Response = Http.Post(fmt::format("/prj/{}/oplog/{}/rpc", "proj0_copy", "oplog0_copy"), Payload); + HttpWaitForCompletion(Servers.GetInstance(1), Response); } ValidateAttachments(1, "proj0_copy", "oplog0_copy"); ValidateOplog(1, "proj0_copy", "oplog0_copy"); @@ -3561,8 +3529,6 @@ TEST_CASE("project.remote") { ScopedTemporaryDirectory TempDir; { - std::string SaveOplogRequest = fmt::format("{}/prj/{}/oplog/{}/rpc", Servers.GetInstance(0).GetBaseUri(), "proj0", "oplog0"); - Session.SetUrl({SaveOplogRequest}); IoBuffer Payload = MakeCbObjectPayload([&](CbObjectWriter& Writer) { Writer << "method"sv << "export"sv; @@ -3583,17 +3549,14 @@ TEST_CASE("project.remote") } Writer << EndObject; // "params" }); - Session.SetBody(AsBody(Payload)); - Session.SetHeader(cpr::Header{{"Content-Type", "application/x-ue-cb"}}); - cpr::Response Response = Session.Post(); - WaitForCompletion(Servers.GetInstance(0), Response); + + HttpClient Http{Servers.GetInstance(0).GetBaseUri()}; + HttpClient::Response Response = Http.Post(fmt::format("/prj/{}/oplog/{}/rpc", "proj0", "oplog0"), Payload); + HttpWaitForCompletion(Servers.GetInstance(0), Response); } { - MakeProject(Session, Servers.GetInstance(1).GetBaseUri(), "proj0_copy"); - MakeOplog(Session, Servers.GetInstance(1).GetBaseUri(), "proj0_copy", "oplog0_copy"); - std::string LoadOplogRequest = - fmt::format("{}/prj/{}/oplog/{}/rpc", Servers.GetInstance(1).GetBaseUri(), "proj0_copy", "oplog0_copy"); - Session.SetUrl({LoadOplogRequest}); + MakeProject(Servers.GetInstance(1).GetBaseUri(), "proj0_copy"); + MakeOplog(Servers.GetInstance(1).GetBaseUri(), "proj0_copy", "oplog0_copy"); IoBuffer Payload = MakeCbObjectPayload([&](CbObjectWriter& Writer) { Writer << "method"sv << "import"sv; @@ -3610,10 +3573,10 @@ TEST_CASE("project.remote") } Writer << EndObject; // "params" }); - Session.SetBody(AsBody(Payload)); - Session.SetHeader(cpr::Header{{"Content-Type", "application/x-ue-cb"}}); - cpr::Response Response = Session.Post(); - WaitForCompletion(Servers.GetInstance(1), Response); + + HttpClient Http{Servers.GetInstance(1).GetBaseUri()}; + HttpClient::Response Response = Http.Post(fmt::format("/prj/{}/oplog/{}/rpc", "proj0_copy", "oplog0_copy"), Payload); + HttpWaitForCompletion(Servers.GetInstance(1), Response); } ValidateAttachments(1, "proj0_copy", "oplog0_copy"); ValidateOplog(1, "proj0_copy", "oplog0_copy"); @@ -3625,11 +3588,8 @@ TEST_CASE("project.remote") { std::string ExportSourceUri = Servers.GetInstance(0).GetBaseUri(); std::string ExportTargetUri = Servers.GetInstance(1).GetBaseUri(); - MakeProject(Session, ExportTargetUri, "proj0_copy"); - MakeOplog(Session, ExportTargetUri, "proj0_copy", "oplog0_copy"); - - std::string SaveOplogRequest = fmt::format("{}/prj/{}/oplog/{}/rpc", ExportSourceUri, "proj0", "oplog0"); - Session.SetUrl({SaveOplogRequest}); + MakeProject(ExportTargetUri, "proj0_copy"); + MakeOplog(ExportTargetUri, "proj0_copy", "oplog0_copy"); IoBuffer Payload = MakeCbObjectPayload([&](CbObjectWriter& Writer) { Writer << "method"sv @@ -3652,10 +3612,10 @@ TEST_CASE("project.remote") } Writer << EndObject; // "params" }); - Session.SetBody(AsBody(Payload)); - Session.SetHeader(cpr::Header{{"Content-Type", "application/x-ue-cb"}}); - cpr::Response Response = Session.Post(); - WaitForCompletion(Servers.GetInstance(0), Response); + + HttpClient Http{Servers.GetInstance(0).GetBaseUri()}; + HttpClient::Response Response = Http.Post(fmt::format("/prj/{}/oplog/{}/rpc", "proj0", "oplog0"), Payload); + HttpWaitForCompletion(Servers.GetInstance(0), Response); } ValidateAttachments(1, "proj0_copy", "oplog0_copy"); ValidateOplog(1, "proj0_copy", "oplog0_copy"); @@ -3663,10 +3623,8 @@ TEST_CASE("project.remote") { std::string ImportSourceUri = Servers.GetInstance(1).GetBaseUri(); std::string ImportTargetUri = Servers.GetInstance(2).GetBaseUri(); - MakeProject(Session, ImportTargetUri, "proj1"); - MakeOplog(Session, ImportTargetUri, "proj1", "oplog1"); - std::string LoadOplogRequest = fmt::format("{}/prj/{}/oplog/{}/rpc", ImportTargetUri, "proj1", "oplog1"); - Session.SetUrl({LoadOplogRequest}); + MakeProject(ImportTargetUri, "proj1"); + MakeOplog(ImportTargetUri, "proj1", "oplog1"); IoBuffer Payload = MakeCbObjectPayload([&](CbObjectWriter& Writer) { Writer << "method"sv @@ -3686,10 +3644,10 @@ TEST_CASE("project.remote") } Writer << EndObject; // "params" }); - Session.SetBody(AsBody(Payload)); - Session.SetHeader(cpr::Header{{"Content-Type", "application/x-ue-cb"}}); - cpr::Response Response = Session.Post(); - WaitForCompletion(Servers.GetInstance(2), Response); + + HttpClient Http{Servers.GetInstance(2).GetBaseUri()}; + HttpClient::Response Response = Http.Post(fmt::format("/prj/{}/oplog/{}/rpc", "proj1", "oplog1"), Payload); + HttpWaitForCompletion(Servers.GetInstance(2), Response); } ValidateAttachments(2, "proj1", "oplog1"); ValidateOplog(2, "proj1", "oplog1"); diff --git a/src/zenserver/cache/httpstructuredcache.cpp b/src/zenserver/cache/httpstructuredcache.cpp index bc3f4ee20..dad4ed803 100644 --- a/src/zenserver/cache/httpstructuredcache.cpp +++ b/src/zenserver/cache/httpstructuredcache.cpp @@ -40,7 +40,6 @@ #include <queue> #include <thread> -#include <cpr/cpr.h> #include <gsl/gsl-lite.hpp> namespace zen { @@ -391,8 +390,9 @@ HttpStructuredCacheService::HandleRequest(HttpServerRequest& Request) if (Key == HttpZCacheUtilStartRecording) { - HttpServerRequest::QueryParams Params = Request.GetQueryParams(); - std::string RecordPath = cpr::util::urlDecode(std::string(Params.GetValue("path"))); + HttpServerRequest::QueryParams Params = Request.GetQueryParams(); + + std::string RecordPath = UrlDecode(Params.GetValue("path")); { RwLock::ExclusiveLockScope _(m_RequestRecordingLock); @@ -429,9 +429,11 @@ HttpStructuredCacheService::HandleRequest(HttpServerRequest& Request) m_RequestRecorder.reset(); } - HttpServerRequest::QueryParams Params = Request.GetQueryParams(); - std::string RecordPath = cpr::util::urlDecode(std::string(Params.GetValue("path"))); - uint32_t ThreadCount = std::thread::hardware_concurrency(); + HttpServerRequest::QueryParams Params = Request.GetQueryParams(); + + std::string RecordPath = UrlDecode(Params.GetValue("path")); + + uint32_t ThreadCount = std::thread::hardware_concurrency(); if (auto Param = Params.GetValue("thread_count"); Param.empty() == false) { if (auto Value = ParseInt<uint64_t>(Param)) diff --git a/src/zenserver/projectstore/buildsremoteprojectstore.cpp b/src/zenserver/projectstore/buildsremoteprojectstore.cpp index 0b0d8ccd0..b8b499f7f 100644 --- a/src/zenserver/projectstore/buildsremoteprojectstore.cpp +++ b/src/zenserver/projectstore/buildsremoteprojectstore.cpp @@ -255,7 +255,9 @@ public: } catch (const HttpClientError& Ex) { - Result.ErrorCode = Ex.m_Error != 0 ? Ex.m_Error : Ex.m_ResponseCode != HttpResponseCode::ImATeapot ? (int)Ex.m_ResponseCode : 0; + Result.ErrorCode = Ex.GetInternalErrorCode() != 0 ? Ex.GetInternalErrorCode() + : Ex.GetHttpResponseCode() != HttpResponseCode::ImATeapot ? (int)Ex.GetHttpResponseCode() + : 0; Result.Reason = fmt::format("Failed finalizing oplog container build part to {}/{}/{}/{}/{}. Reason: '{}'", m_Url, m_Namespace, @@ -284,9 +286,9 @@ public: } catch (const HttpClientError& Ex) { - Result.ErrorCode = Ex.m_Error != 0 ? Ex.m_Error - : Ex.m_ResponseCode != HttpResponseCode::ImATeapot ? (int)Ex.m_ResponseCode - : 0; + Result.ErrorCode = Ex.GetInternalErrorCode() != 0 ? Ex.GetInternalErrorCode() + : Ex.GetHttpResponseCode() != HttpResponseCode::ImATeapot ? (int)Ex.GetHttpResponseCode() + : 0; Result.Reason = fmt::format("Failed finalizing oplog container build to {}/{}/{}/{}. Reason: '{}'", m_Url, m_Namespace, @@ -452,7 +454,9 @@ public: private: static int MakeErrorCode(const HttpClientError& Ex) { - return Ex.m_Error != 0 ? Ex.m_Error : Ex.m_ResponseCode != HttpResponseCode::ImATeapot ? (int)Ex.m_ResponseCode : 0; + return Ex.GetInternalErrorCode() != 0 ? Ex.GetInternalErrorCode() + : Ex.GetHttpResponseCode() != HttpResponseCode::ImATeapot ? (int)Ex.GetHttpResponseCode() + : 0; } std::unique_ptr<BuildStorage::Statistics> m_BuildStorageStats; diff --git a/src/zenserver/projectstore/projectstore.cpp b/src/zenserver/projectstore/projectstore.cpp index 262b35ea2..690f697d0 100644 --- a/src/zenserver/projectstore/projectstore.cpp +++ b/src/zenserver/projectstore/projectstore.cpp @@ -34,7 +34,6 @@ #include "zenremoteprojectstore.h" ZEN_THIRD_PARTY_INCLUDES_START -#include <cpr/cpr.h> #include <tsl/robin_set.h> #include <xxh3.h> ZEN_THIRD_PARTY_INCLUDES_END @@ -192,7 +191,7 @@ namespace { return {nullptr, "Missing service url"}; } - std::string Url = cpr::util::urlDecode(std::string(CloudServiceUrl)); + std::string Url = UrlDecode(CloudServiceUrl); std::string_view Namespace = Cloud["namespace"sv].AsString(); if (Namespace.empty()) { @@ -302,7 +301,7 @@ namespace { return {nullptr, "Missing service url"}; } - std::string Url = cpr::util::urlDecode(std::string(BuildsServiceUrl)); + std::string Url = UrlDecode(BuildsServiceUrl); std::string_view Namespace = Builds["namespace"sv].AsString(); if (Namespace.empty()) { diff --git a/src/zenserver/upstream/zen.cpp b/src/zenserver/upstream/zen.cpp index 7494ae379..25fd3a3bb 100644 --- a/src/zenserver/upstream/zen.cpp +++ b/src/zenserver/upstream/zen.cpp @@ -9,44 +9,18 @@ #include <zencore/session.h> #include <zencore/stream.h> #include <zenhttp/formatters.h> +#include <zenhttp/httpclient.h> #include <zenhttp/httpcommon.h> #include <zenhttp/packageformat.h> #include <zenstore/cache/structuredcachestore.h> #include "diag/logging.h" -ZEN_THIRD_PARTY_INCLUDES_START -#include <cpr/cpr.h> -ZEN_THIRD_PARTY_INCLUDES_END - #include <xxhash.h> #include <gsl/gsl-lite.hpp> namespace zen { -namespace detail { - struct ZenCacheSessionState - { - ZenCacheSessionState(ZenStructuredCacheClient& Client) : OwnerClient(Client) {} - ~ZenCacheSessionState() {} - - void Reset(std::chrono::milliseconds ConnectTimeout, std::chrono::milliseconds Timeout) - { - Session.SetBody({}); - Session.SetHeader({}); - Session.SetConnectTimeout(ConnectTimeout); - Session.SetTimeout(Timeout); - } - - cpr::Session& GetSession() { return Session; } - - private: - ZenStructuredCacheClient& OwnerClient; - cpr::Session Session; - }; - -} // namespace detail - ////////////////////////////////////////////////////////////////////////// ZenStructuredCacheClient::ZenStructuredCacheClient(const ZenStructuredCacheClientOptions& Options) @@ -59,39 +33,6 @@ ZenStructuredCacheClient::ZenStructuredCacheClient(const ZenStructuredCacheClien ZenStructuredCacheClient::~ZenStructuredCacheClient() { - RwLock::ExclusiveLockScope _(m_SessionStateLock); - for (auto& CacheEntry : m_SessionStateCache) - { - delete CacheEntry; - } -} - -detail::ZenCacheSessionState* -ZenStructuredCacheClient::AllocSessionState() -{ - detail::ZenCacheSessionState* State = nullptr; - - if (RwLock::ExclusiveLockScope _(m_SessionStateLock); !m_SessionStateCache.empty()) - { - State = m_SessionStateCache.front(); - m_SessionStateCache.pop_front(); - } - - if (State == nullptr) - { - State = new detail::ZenCacheSessionState(*this); - } - - State->Reset(m_ConnectTimeout, m_Timeout); - - return State; -} - -void -ZenStructuredCacheClient::FreeSessionState(detail::ZenCacheSessionState* State) -{ - RwLock::ExclusiveLockScope _(m_SessionStateLock); - m_SessionStateCache.push_front(State); } ////////////////////////////////////////////////////////////////////////// @@ -102,59 +43,54 @@ ZenStructuredCacheSession::ZenStructuredCacheSession(Ref<ZenStructuredCacheClien : m_Log(OuterClient->Log()) , m_Client(std::move(OuterClient)) { - m_SessionState = m_Client->AllocSessionState(); } ZenStructuredCacheSession::~ZenStructuredCacheSession() { - m_Client->FreeSessionState(m_SessionState); } ZenCacheResult ZenStructuredCacheSession::CheckHealth() { - ExtendableStringBuilder<256> Uri; - Uri << m_Client->ServiceUrl() << "/health/check"; + HttpClient Http{m_Client->ServiceUrl()}; - cpr::Session& Session = m_SessionState->GetSession(); - Session.SetOption(cpr::Url{Uri.c_str()}); - cpr::Response Response = Session.Get(); + HttpClient::Response Response = Http.Get("/health/check"sv); - if (Response.error) + if (auto& Error = Response.Error; Error) { - return {.ErrorCode = static_cast<int32_t>(Response.error.code), .Reason = std::move(Response.error.message)}; + return {.ErrorCode = static_cast<int32_t>(Error->ErrorCode), .Reason = std::move(Error->ErrorMessage)}; } - return {.Bytes = Response.downloaded_bytes, .ElapsedSeconds = Response.elapsed, .Success = Response.status_code == 200}; + return {.Bytes = Response.DownloadedBytes, + .ElapsedSeconds = Response.ElapsedSeconds, + .Success = Response.StatusCode == HttpResponseCode::OK}; } ZenCacheResult ZenStructuredCacheSession::GetCacheRecord(std::string_view Namespace, std::string_view BucketId, const IoHash& Key, ZenContentType Type) { + HttpClient Http{m_Client->ServiceUrl()}; + ExtendableStringBuilder<256> Uri; - Uri << m_Client->ServiceUrl() << "/z$/"; + Uri << "/z$/"; if (Namespace != ZenCacheStore::DefaultNamespace) { Uri << Namespace << "/"; } Uri << BucketId << "/" << Key.ToHexString(); - cpr::Session& Session = m_SessionState->GetSession(); - - Session.SetOption(cpr::Url{Uri.c_str()}); - Session.SetHeader(cpr::Header{{"Accept", std::string{MapContentTypeToString(Type)}}}); - cpr::Response Response = Session.Get(); + HttpClient::Response Response = Http.Get(Uri, {{"Accept", std::string{MapContentTypeToString(Type)}}}); ZEN_DEBUG("GET {}", Response); - if (Response.error) + if (auto& Error = Response.Error; Error) { - return {.ErrorCode = static_cast<int32_t>(Response.error.code), .Reason = std::move(Response.error.message)}; + return {.ErrorCode = static_cast<int32_t>(Error->ErrorCode), .Reason = std::move(Error->ErrorMessage)}; } - const bool Success = Response.status_code == 200; - const IoBuffer Buffer = Success ? IoBufferBuilder::MakeCloneFromMemory(Response.text.data(), Response.text.size()) : IoBuffer(); + const bool Success = Response.StatusCode == HttpResponseCode::OK; + const IoBuffer Buffer = Success ? Response.ResponsePayload : IoBuffer{}; - return {.Response = Buffer, .Bytes = Response.downloaded_bytes, .ElapsedSeconds = Response.elapsed, .Success = Success}; + return {.Response = Buffer, .Bytes = Response.DownloadedBytes, .ElapsedSeconds = Response.ElapsedSeconds, .Success = Success}; } ZenCacheResult @@ -163,35 +99,28 @@ ZenStructuredCacheSession::GetCacheChunk(std::string_view Namespace, const IoHash& Key, const IoHash& ValueContentId) { + HttpClient Http{m_Client->ServiceUrl()}; + ExtendableStringBuilder<256> Uri; - Uri << m_Client->ServiceUrl() << "/z$/"; + Uri << "/z$/"; if (Namespace != ZenCacheStore::DefaultNamespace) { Uri << Namespace << "/"; } Uri << BucketId << "/" << Key.ToHexString() << "/" << ValueContentId.ToHexString(); - cpr::Session& Session = m_SessionState->GetSession(); - - Session.SetOption(cpr::Url{Uri.c_str()}); - Session.SetHeader(cpr::Header{{"Accept", "application/x-ue-comp"}}); - - cpr::Response Response = Session.Get(); + HttpClient::Response Response = Http.Get(Uri, {{"Accept", "application/x-ue-comp"}}); ZEN_DEBUG("GET {}", Response); - if (Response.error) + if (auto& Error = Response.Error; Error) { - return {.ErrorCode = static_cast<int32_t>(Response.error.code), .Reason = std::move(Response.error.message)}; + return {.ErrorCode = static_cast<int32_t>(Error->ErrorCode), .Reason = std::move(Error->ErrorMessage)}; } - const bool Success = Response.status_code == 200; - const IoBuffer Buffer = Success ? IoBufferBuilder::MakeCloneFromMemory(Response.text.data(), Response.text.size()) : IoBuffer(); + const bool Success = Response.StatusCode == HttpResponseCode::OK; + const IoBuffer Buffer = Success ? Response.ResponsePayload : IoBuffer{}; - return {.Response = Buffer, - .Bytes = Response.downloaded_bytes, - .ElapsedSeconds = Response.elapsed, - .Reason = Response.reason, - .Success = Success}; + return {.Response = Buffer, .Bytes = Response.DownloadedBytes, .ElapsedSeconds = Response.ElapsedSeconds, .Success = Success}; } ZenCacheResult @@ -201,33 +130,29 @@ ZenStructuredCacheSession::PutCacheRecord(std::string_view Namespace, IoBuffer Value, ZenContentType Type) { + HttpClient Http{m_Client->ServiceUrl()}; + ExtendableStringBuilder<256> Uri; - Uri << m_Client->ServiceUrl() << "/z$/"; + Uri << "/z$/"; if (Namespace != ZenCacheStore::DefaultNamespace) { Uri << Namespace << "/"; } Uri << BucketId << "/" << Key.ToHexString(); - cpr::Session& Session = m_SessionState->GetSession(); - - Session.SetOption(cpr::Url{Uri.c_str()}); - Session.SetHeader(cpr::Header{{"Content-Type", - Type == ZenContentType::kCbPackage ? "application/x-ue-cbpkg" - : Type == ZenContentType::kCbObject ? "application/x-ue-cb" - : "application/octet-stream"}}); - Session.SetBody(cpr::Body{static_cast<const char*>(Value.Data()), Value.Size()}); + Value.SetContentType(Type); - cpr::Response Response = Session.Put(); + HttpClient::Response Response = Http.Put(Uri, Value); ZEN_DEBUG("PUT {}", Response); - if (Response.error) + if (auto& Error = Response.Error; Error) { - return {.ErrorCode = static_cast<int32_t>(Response.error.code), .Reason = std::move(Response.error.message)}; + return {.ErrorCode = static_cast<int32_t>(Error->ErrorCode), .Reason = std::move(Error->ErrorMessage)}; } - const bool Success = Response.status_code == 200 || Response.status_code == 201; - return {.Bytes = Response.uploaded_bytes, .ElapsedSeconds = Response.elapsed, .Reason = Response.reason, .Success = Success}; + const bool Success = Response.StatusCode == HttpResponseCode::OK || Response.StatusCode == HttpResponseCode::Created; + + return {.Bytes = Response.DownloadedBytes, .ElapsedSeconds = Response.ElapsedSeconds, .Success = Success}; } ZenCacheResult @@ -237,94 +162,89 @@ ZenStructuredCacheSession::PutCacheValue(std::string_view Namespace, const IoHash& ValueContentId, IoBuffer Payload) { + HttpClient Http{m_Client->ServiceUrl()}; + ExtendableStringBuilder<256> Uri; - Uri << m_Client->ServiceUrl() << "/z$/"; + Uri << "/z$/"; if (Namespace != ZenCacheStore::DefaultNamespace) { Uri << Namespace << "/"; } Uri << BucketId << "/" << Key.ToHexString() << "/" << ValueContentId.ToHexString(); - cpr::Session& Session = m_SessionState->GetSession(); - - Session.SetOption(cpr::Url{Uri.c_str()}); - Session.SetHeader(cpr::Header{{"Content-Type", "application/x-ue-comp"}}); - Session.SetBody(cpr::Body{static_cast<const char*>(Payload.Data()), Payload.Size()}); + Payload.SetContentType(HttpContentType::kCompressedBinary); - cpr::Response Response = Session.Put(); + HttpClient::Response Response = Http.Put(Uri, Payload); ZEN_DEBUG("PUT {}", Response); - if (Response.error) + if (auto& Error = Response.Error; Error) { - return {.ErrorCode = static_cast<int32_t>(Response.error.code), .Reason = std::move(Response.error.message)}; + return {.ErrorCode = static_cast<int32_t>(Error->ErrorCode), .Reason = std::move(Error->ErrorMessage)}; } - const bool Success = Response.status_code == 200 || Response.status_code == 201; - return {.Bytes = Response.uploaded_bytes, .ElapsedSeconds = Response.elapsed, .Reason = Response.reason, .Success = Success}; + const bool Success = Response.StatusCode == HttpResponseCode::OK || Response.StatusCode == HttpResponseCode::Created; + + return {.Bytes = Response.DownloadedBytes, .ElapsedSeconds = Response.ElapsedSeconds, .Success = Success}; } ZenCacheResult ZenStructuredCacheSession::InvokeRpc(const CbObjectView& Request) { + HttpClient Http{m_Client->ServiceUrl()}; + ExtendableStringBuilder<256> Uri; - Uri << m_Client->ServiceUrl() << "/z$/$rpc"; + Uri << "/z$/$rpc"; - BinaryWriter Body; - Request.CopyTo(Body); + // TODO: this seems redundant, we should be able to send the data more directly, without the BinaryWriter - cpr::Session& Session = m_SessionState->GetSession(); + BinaryWriter BodyWriter; + Request.CopyTo(BodyWriter); - Session.SetOption(cpr::Url{Uri.c_str()}); - Session.SetHeader(cpr::Header{{"Content-Type", "application/x-ue-cb"}, {"Accept", "application/x-ue-cbpkg"}}); - Session.SetBody(cpr::Body{reinterpret_cast<const char*>(Body.GetData()), Body.GetSize()}); + IoBuffer Body{IoBuffer::Wrap, BodyWriter.GetData(), BodyWriter.GetSize()}; + Body.SetContentType(HttpContentType::kCbObject); - cpr::Response Response = Session.Post(); + HttpClient::Response Response = Http.Post(Uri, Body, {{"Accept", "application/x-ue-cbpkg"}}); ZEN_DEBUG("POST {}", Response); - if (Response.error) + if (auto& Error = Response.Error; Error) { - return {.ErrorCode = static_cast<int32_t>(Response.error.code), .Reason = std::move(Response.error.message)}; + return {.ErrorCode = static_cast<int32_t>(Error->ErrorCode), .Reason = std::move(Error->ErrorMessage)}; } - const bool Success = Response.status_code == 200; - const IoBuffer Buffer = Success ? IoBufferBuilder::MakeCloneFromMemory(Response.text.data(), Response.text.size()) : IoBuffer(); + const bool Success = Response.StatusCode == HttpResponseCode::OK; + const IoBuffer Buffer = Success ? Response.ResponsePayload : IoBuffer{}; return {.Response = std::move(Buffer), - .Bytes = Response.uploaded_bytes, - .ElapsedSeconds = Response.elapsed, - .Reason = Response.reason, + .Bytes = Response.DownloadedBytes, + .ElapsedSeconds = Response.ElapsedSeconds, .Success = Success}; } ZenCacheResult ZenStructuredCacheSession::InvokeRpc(const CbPackage& Request) { - ExtendableStringBuilder<256> Uri; - Uri << m_Client->ServiceUrl() << "/z$/$rpc"; + HttpClient Http{m_Client->ServiceUrl()}; - SharedBuffer Message = FormatPackageMessageBuffer(Request).Flatten(); - - cpr::Session& Session = m_SessionState->GetSession(); + ExtendableStringBuilder<256> Uri; + Uri << "/z$/$rpc"; - Session.SetOption(cpr::Url{Uri.c_str()}); - Session.SetHeader(cpr::Header{{"Content-Type", "application/x-ue-cbpkg"}, {"Accept", "application/x-ue-cbpkg"}}); - Session.SetBody(cpr::Body{reinterpret_cast<const char*>(Message.GetData()), Message.GetSize()}); + IoBuffer Message = FormatPackageMessageBuffer(Request).Flatten().AsIoBuffer(); + Message.SetContentType(HttpContentType::kCbPackage); - cpr::Response Response = Session.Post(); + HttpClient::Response Response = Http.Post(Uri, Message, {{"Accept", "application/x-ue-cbpkg"}}); ZEN_DEBUG("POST {}", Response); - if (Response.error) + if (auto& Error = Response.Error; Error) { - return {.ErrorCode = static_cast<int32_t>(Response.error.code), .Reason = std::move(Response.error.message)}; + return {.ErrorCode = static_cast<int32_t>(Error->ErrorCode), .Reason = std::move(Error->ErrorMessage)}; } - const bool Success = Response.status_code == 200; - const IoBuffer Buffer = Success ? IoBufferBuilder::MakeCloneFromMemory(Response.text.data(), Response.text.size()) : IoBuffer(); + const bool Success = Response.StatusCode == HttpResponseCode::OK; + const IoBuffer Buffer = Success ? Response.ResponsePayload : IoBuffer{}; return {.Response = std::move(Buffer), - .Bytes = Response.uploaded_bytes, - .ElapsedSeconds = Response.elapsed, - .Reason = Response.reason, + .Bytes = Response.DownloadedBytes, + .ElapsedSeconds = Response.ElapsedSeconds, .Success = Success}; } diff --git a/src/zenserver/upstream/zen.h b/src/zenserver/upstream/zen.h index 78b6bc589..6321b46b1 100644 --- a/src/zenserver/upstream/zen.h +++ b/src/zenserver/upstream/zen.h @@ -6,17 +6,10 @@ #include <zencore/iohash.h> #include <zencore/logging.h> #include <zencore/memoryview.h> -#include <zencore/thread.h> #include <zencore/uid.h> #include <zencore/zencore.h> -ZEN_THIRD_PARTY_INCLUDES_START -#include <tsl/robin_map.h> -#include <asio.hpp> -ZEN_THIRD_PARTY_INCLUDES_END - #include <chrono> -#include <list> struct ZenCacheValue; @@ -29,10 +22,6 @@ class ZenStructuredCacheClient; ////////////////////////////////////////////////////////////////////////// -namespace detail { - struct ZenCacheSessionState; -} - struct ZenCacheResult { IoBuffer Response; @@ -85,7 +74,6 @@ private: LoggerRef m_Log; Ref<ZenStructuredCacheClient> m_Client; - detail::ZenCacheSessionState* m_SessionState; }; /** Zen Structured Cache client @@ -109,12 +97,6 @@ private: std::chrono::milliseconds m_ConnectTimeout; std::chrono::milliseconds m_Timeout; - RwLock m_SessionStateLock; - std::list<detail::ZenCacheSessionState*> m_SessionStateCache; - - detail::ZenCacheSessionState* AllocSessionState(); - void FreeSessionState(detail::ZenCacheSessionState*); - friend class ZenStructuredCacheSession; }; diff --git a/src/zenutil/zenserverprocess.cpp b/src/zenutil/zenserverprocess.cpp index 3f71c1357..36211263a 100644 --- a/src/zenutil/zenserverprocess.cpp +++ b/src/zenutil/zenserverprocess.cpp @@ -656,7 +656,7 @@ ZenServerInstance::Shutdown() } else if (Ec) { - ZEN_WARN("Terminating zenserver proces as we failed to signal zenserver process {} ({}) to shut down. Reason: '{}'", + ZEN_WARN("Terminating zenserver process as we failed to signal zenserver process {} ({}) to shut down. Reason: '{}'", m_Name, m_Process.Pid(), Ec.message()); |