diff options
Diffstat (limited to 'src')
| -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()); |