diff options
| author | Stefan Boberg <[email protected]> | 2021-09-29 13:30:36 +0200 |
|---|---|---|
| committer | Stefan Boberg <[email protected]> | 2021-09-29 13:30:36 +0200 |
| commit | 6bbea2f29d349b64b840a8345d9c189ec08c76f8 (patch) | |
| tree | 9d56d62eab9d2543a8c81c252fa842fc3e0c03af | |
| parent | string: Fixed some clang warnings (diff) | |
| parent | Removing deprecated RefPtr+stack based objects tests (diff) | |
| download | zen-6bbea2f29d349b64b840a8345d9c189ec08c76f8.tar.xz zen-6bbea2f29d349b64b840a8345d9c189ec08c76f8.zip | |
Merge branch 'main' of https://github.com/EpicGames/zen
| -rw-r--r-- | zencore/refcount.cpp | 36 | ||||
| -rw-r--r-- | zenhttp/httpserver.cpp | 116 | ||||
| -rw-r--r-- | zenhttp/httpsys.cpp | 105 | ||||
| -rw-r--r-- | zenhttp/httpuws.cpp | 24 | ||||
| -rw-r--r-- | zenhttp/include/zenhttp/httpcommon.h | 2 | ||||
| -rw-r--r-- | zenserver/upstream/jupiter.cpp | 258 | ||||
| -rw-r--r-- | zenserver/upstream/jupiter.h | 12 |
7 files changed, 390 insertions, 163 deletions
diff --git a/zencore/refcount.cpp b/zencore/refcount.cpp index 33b530b90..c6c47b04d 100644 --- a/zencore/refcount.cpp +++ b/zencore/refcount.cpp @@ -60,42 +60,6 @@ TEST_CASE("RefPtr") CHECK(IsDestroyed == true); } -TEST_CASE("RefPtr on Stack allocated object") -{ - bool IsDestroyed = false; - - { - TestRefClass StackRefClass; - - StackRefClass.OnDestroy = [&] { IsDestroyed = true; }; - - CHECK(StackRefClass.RefCount() == 1); // Stack allocated objects should have +1 ref - - RefPtr<TestRefClass> Ref{&StackRefClass}; - - CHECK(IsDestroyed == false); - CHECK(StackRefClass.RefCount() == 2); - - RefPtr<TestRefClass> Ref2; - Ref2 = Ref; - - CHECK(IsDestroyed == false); - CHECK(StackRefClass.RefCount() == 3); - - RefPtr<TestRefClass> Ref3; - Ref2 = Ref3; - - CHECK(IsDestroyed == false); - CHECK(StackRefClass.RefCount() == 2); - - Ref = Ref3; - CHECK(IsDestroyed == false); - CHECK(StackRefClass.RefCount() == 1); - } - - CHECK(IsDestroyed == true); -} - #endif } // namespace zen diff --git a/zenhttp/httpserver.cpp b/zenhttp/httpserver.cpp index 795e81ea8..8e5d61877 100644 --- a/zenhttp/httpserver.cpp +++ b/zenhttp/httpserver.cpp @@ -152,7 +152,7 @@ ToString(HttpVerb Verb) } } -const char* +std::string_view ReasonStringForHttpResultCode(int HttpCode) { switch (HttpCode) @@ -160,132 +160,132 @@ ReasonStringForHttpResultCode(int HttpCode) // 1xx Informational case 100: - return "Continue"; + return "Continue"sv; case 101: - return "Switching Protocols"; + return "Switching Protocols"sv; // 2xx Success case 200: - return "OK"; + return "OK"sv; case 201: - return "Created"; + return "Created"sv; case 202: - return "Accepted"; + return "Accepted"sv; case 204: - return "No Content"; + return "No Content"sv; case 205: - return "Reset Content"; + return "Reset Content"sv; case 206: - return "Partial Content"; + return "Partial Content"sv; // 3xx Redirection case 300: - return "Multiple Choices"; + return "Multiple Choices"sv; case 301: - return "Moved Permanently"; + return "Moved Permanently"sv; case 302: - return "Found"; + return "Found"sv; case 303: - return "See Other"; + return "See Other"sv; case 304: - return "Not Modified"; + return "Not Modified"sv; case 305: - return "Use Proxy"; + return "Use Proxy"sv; case 306: - return "Switch Proxy"; + return "Switch Proxy"sv; case 307: - return "Temporary Redirect"; + return "Temporary Redirect"sv; case 308: - return "Permanent Redirect"; + return "Permanent Redirect"sv; // 4xx Client errors case 400: - return "Bad Request"; + return "Bad Request"sv; case 401: - return "Unauthorized"; + return "Unauthorized"sv; case 402: - return "Payment Required"; + return "Payment Required"sv; case 403: - return "Forbidden"; + return "Forbidden"sv; case 404: - return "Not Found"; + return "Not Found"sv; case 405: - return "Method Not Allowed"; + return "Method Not Allowed"sv; case 406: - return "Not Acceptable"; + return "Not Acceptable"sv; case 407: - return "Proxy Authentication Required"; + return "Proxy Authentication Required"sv; case 408: - return "Request Timeout"; + return "Request Timeout"sv; case 409: - return "Conflict"; + return "Conflict"sv; case 410: - return "Gone"; + return "Gone"sv; case 411: - return "Length Required"; + return "Length Required"sv; case 412: - return "Precondition Failed"; + return "Precondition Failed"sv; case 413: - return "Payload Too Large"; + return "Payload Too Large"sv; case 414: - return "URI Too Long"; + return "URI Too Long"sv; case 415: - return "Unsupported Media Type"; + return "Unsupported Media Type"sv; case 416: - return "Range Not Satisifiable"; + return "Range Not Satisifiable"sv; case 417: - return "Expectation Failed"; + return "Expectation Failed"sv; case 418: - return "I'm a teapot"; + return "I'm a teapot"sv; case 421: - return "Misdirected Request"; + return "Misdirected Request"sv; case 422: - return "Unprocessable Entity"; + return "Unprocessable Entity"sv; case 423: - return "Locked"; + return "Locked"sv; case 424: - return "Failed Dependency"; + return "Failed Dependency"sv; case 425: - return "Too Early"; + return "Too Early"sv; case 426: - return "Upgrade Required"; + return "Upgrade Required"sv; case 428: - return "Precondition Required"; + return "Precondition Required"sv; case 429: - return "Too Many Requests"; + return "Too Many Requests"sv; case 431: - return "Request Header Fields Too Large"; + return "Request Header Fields Too Large"sv; // 5xx Server errors case 500: - return "Internal Server Error"; + return "Internal Server Error"sv; case 501: - return "Not Implemented"; + return "Not Implemented"sv; case 502: - return "Bad Gateway"; + return "Bad Gateway"sv; case 503: - return "Service Unavailable"; + return "Service Unavailable"sv; case 504: - return "Gateway Timeout"; + return "Gateway Timeout"sv; case 505: - return "HTTP Version Not Supported"; + return "HTTP Version Not Supported"sv; case 506: - return "Variant Also Negotiates"; + return "Variant Also Negotiates"sv; case 507: - return "Insufficient Storage"; + return "Insufficient Storage"sv; case 508: - return "Loop Detected"; + return "Loop Detected"sv; case 510: - return "Not Extended"; + return "Not Extended"sv; case 511: - return "Network Authentication Required"; + return "Network Authentication Required"sv; default: - return "Unknown Result"; + return "Unknown Result"sv; } } diff --git a/zenhttp/httpsys.cpp b/zenhttp/httpsys.cpp index bccff24ab..9b2e7f832 100644 --- a/zenhttp/httpsys.cpp +++ b/zenhttp/httpsys.cpp @@ -18,47 +18,43 @@ # pragma comment(lib, "httpapi.lib") std::wstring -UTF8_to_wstring(const char* in) +UTF8_to_UTF16(const char* InPtr) { - std::wstring out; - unsigned int codepoint; + std::wstring OutString; + unsigned int Codepoint; - while (*in != 0) + while (*InPtr != 0) { - unsigned char ch = static_cast<unsigned char>(*in); - - if (ch <= 0x7f) - codepoint = ch; - else if (ch <= 0xbf) - codepoint = (codepoint << 6) | (ch & 0x3f); - else if (ch <= 0xdf) - codepoint = ch & 0x1f; - else if (ch <= 0xef) - codepoint = ch & 0x0f; + unsigned char InChar = static_cast<unsigned char>(*InPtr); + + if (InChar <= 0x7f) + Codepoint = InChar; + else if (InChar <= 0xbf) + Codepoint = (Codepoint << 6) | (InChar & 0x3f); + else if (InChar <= 0xdf) + Codepoint = InChar & 0x1f; + else if (InChar <= 0xef) + Codepoint = InChar & 0x0f; else - codepoint = ch & 0x07; + Codepoint = InChar & 0x07; - ++in; + ++InPtr; - if (((*in & 0xc0) != 0x80) && (codepoint <= 0x10ffff)) + if (((*InPtr & 0xc0) != 0x80) && (Codepoint <= 0x10ffff)) { - if constexpr (sizeof(wchar_t) > 2) + if (Codepoint > 0xffff) { - out.append(1, static_cast<wchar_t>(codepoint)); + OutString.append(1, static_cast<wchar_t>(0xd800 + (Codepoint >> 10))); + OutString.append(1, static_cast<wchar_t>(0xdc00 + (Codepoint & 0x03ff))); } - else if (codepoint > 0xffff) + else if (Codepoint < 0xd800 || Codepoint >= 0xe000) { - out.append(1, static_cast<wchar_t>(0xd800 + (codepoint >> 10))); - out.append(1, static_cast<wchar_t>(0xdc00 + (codepoint & 0x03ff))); - } - else if (codepoint < 0xd800 || codepoint >= 0xe000) - { - out.append(1, static_cast<wchar_t>(codepoint)); + OutString.append(1, static_cast<wchar_t>(Codepoint)); } } } - return out; + return OutString; } namespace zen { @@ -493,6 +489,7 @@ HttpMessageResponseRequest::IssueRequest(std::error_code& ErrorCode) // Computer\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\HTTP\Parameters // // Set DisableServerHeader to 1 to disable suffix, or 2 to disable the header altogether + // (only the latter appears to do anything in my testing, on Windows 10). // // (reference https://docs.microsoft.com/en-us/archive/blogs/dsnotes/wswcf-remove-server-header) // @@ -519,9 +516,11 @@ HttpMessageResponseRequest::IssueRequest(std::error_code& ErrorCode) ContentTypeHeader->pRawValue = ContentTypeString.data(); ContentTypeHeader->RawValueLength = (USHORT)ContentTypeString.size(); + std::string_view ReasonString = ReasonStringForHttpResultCode(m_ResponseCode); + HttpResponse.StatusCode = m_ResponseCode; - HttpResponse.pReason = ReasonStringForHttpResultCode(m_ResponseCode); - HttpResponse.ReasonLength = (USHORT)strlen(HttpResponse.pReason); + HttpResponse.pReason = ReasonString.data(); + HttpResponse.ReasonLength = (USHORT)ReasonString.size(); // Cache policy @@ -823,18 +822,18 @@ HttpSysServer::RegisterService(const char* UrlPath, HttpService& Service) ++UrlPath; } - const std::wstring Path16 = UTF8_to_wstring(UrlPath); - Service.SetUriPrefixLength(Path16.size() + 1 /* leading slash */); + const std::wstring PathUtf16 = UTF8_to_UTF16(UrlPath); + Service.SetUriPrefixLength(PathUtf16.size() + 1 /* leading slash */); // Convert to wide string - std::wstring Url16 = m_BaseUri + Path16; + std::wstring Url16 = m_BaseUri + PathUtf16; ULONG Result = HttpAddUrlToUrlGroup(m_HttpUrlGroupId, Url16.c_str(), HTTP_URL_CONTEXT(&Service), 0 /* Reserved */); if (Result != NO_ERROR) { - ZEN_ERROR("HttpAddUrlToUrlGroup failed with result {}", Result); + ZEN_ERROR("HttpAddUrlToUrlGroup failed with result: '{}'", GetSystemErrorAsString(Result)); return; } @@ -850,17 +849,17 @@ HttpSysServer::UnregisterService(const char* UrlPath, HttpService& Service) ++UrlPath; } - const std::wstring Path16 = UTF8_to_wstring(UrlPath); + const std::wstring PathUtf16 = UTF8_to_UTF16(UrlPath); // Convert to wide string - std::wstring Url16 = m_BaseUri + Path16; + std::wstring Url16 = m_BaseUri + PathUtf16; ULONG Result = HttpRemoveUrlFromUrlGroup(m_HttpUrlGroupId, Url16.c_str(), 0); if (Result != NO_ERROR) { - ZEN_ERROR("HttpRemoveUrlFromUrlGroup failed with result {}", Result); + ZEN_ERROR("HttpRemoveUrlFromUrlGroup failed with result: '{}'", GetSystemErrorAsString(Result)); } } @@ -1269,7 +1268,7 @@ InitialRequestHandler::IssueRequest(std::error_code& ErrorCode) ErrorCode = MakeErrorCode(HttpApiResult); - ZEN_ERROR("HttpReceiveHttpRequest failed, error {}", ErrorCode.message()); + ZEN_ERROR("HttpReceiveHttpRequest failed, error: '{}'", ErrorCode.message()); return; } @@ -1293,7 +1292,7 @@ InitialRequestHandler::HandleCompletion(ULONG IoResult, ULONG_PTR NumberOfBytesT break; } - // Route requests + // Route request try { @@ -1400,28 +1399,26 @@ InitialRequestHandler::HandleCompletion(ULONG IoResult, ULONG_PTR NumberOfBytesT m_CurrentPayloadOffset += NumberOfBytesTransferred; } - if (m_CurrentPayloadOffset == m_ContentLength) + if (m_CurrentPayloadOffset != m_ContentLength) { - m_PayloadBuffer.MakeImmutable(); + // Body not complete, issue another read request to receive more body data + return this; + } - // Body received completely - call request handler + // Request body received completely - HttpSysServerRequest& ThisRequest = Transaction().InvokeRequestHandler(*Service, m_PayloadBuffer); + m_PayloadBuffer.MakeImmutable(); - if (!ThisRequest.IsHandled()) - { - return new HttpMessageResponseRequest(Transaction(), 404, "Not found"sv); - } + HttpSysServerRequest& ThisRequest = Transaction().InvokeRequestHandler(*Service, m_PayloadBuffer); - if (HttpMessageResponseRequest* Response = ThisRequest.m_Response) - { - return Response; - } + if (!ThisRequest.IsHandled()) + { + return new HttpMessageResponseRequest(Transaction(), 404, "Not found"sv); } - else + + if (HttpMessageResponseRequest* Response = ThisRequest.m_Response) { - // Issue a read request for more body data - return this; + return Response; } } @@ -1430,7 +1427,7 @@ InitialRequestHandler::HandleCompletion(ULONG IoResult, ULONG_PTR NumberOfBytesT } catch (std::exception& ex) { - // TODO provide more meaningful error output + ZEN_ERROR("Caught exception while handling request: '{}'", ex.what()); return new HttpMessageResponseRequest(Transaction(), 500, ex.what()); } diff --git a/zenhttp/httpuws.cpp b/zenhttp/httpuws.cpp index e062e7747..2a6950532 100644 --- a/zenhttp/httpuws.cpp +++ b/zenhttp/httpuws.cpp @@ -12,6 +12,7 @@ #if ZEN_PLATFORM_WINDOWS # pragma comment(lib, "Iphlpapi.lib") +# pragma comment(lib, "userenv.lib") #endif namespace zen { @@ -43,26 +44,21 @@ HttpUwsServer::Run(bool IsInteractive) if (TestMode == false) { - zen::logging::ConsoleLog().info("Zen Server running (null HTTP). Press ESC or Q to quit"); + zen::logging::ConsoleLog().info("Zen Server running (uWS HTTP). Press ESC or Q to quit"); } ::uWS::App() - .get("/*", + .any("/*", [](uWS::HttpResponse<false>* res, uWS::HttpRequest* req) { - res->end("Hello world!"); + res->onData([=](std::string_view Data, bool fin) { + ZEN_UNUSED(Data); + if (fin) + res->end("Hello world!"); + }); + + res->onAborted([&] {}); ZEN_UNUSED(req); }) - .post("/*", - [](uWS::HttpResponse<false>* res, uWS::HttpRequest* req) { - res->onData([&](std::string_view Data, bool fin) { - ZEN_UNUSED(Data); - if (fin) - res->end("Hello world!"); - }); - - res->onAborted([&] {}); - ZEN_UNUSED(req); - }) .listen(m_BasePort, [](auto* listen_socket) { ZEN_UNUSED(listen_socket); }) .run(); diff --git a/zenhttp/include/zenhttp/httpcommon.h b/zenhttp/include/zenhttp/httpcommon.h index 62070061c..3e213ece4 100644 --- a/zenhttp/include/zenhttp/httpcommon.h +++ b/zenhttp/include/zenhttp/httpcommon.h @@ -19,7 +19,7 @@ class StringBuilderBase; std::string_view MapContentTypeToString(HttpContentType ContentType); extern HttpContentType (*ParseContentType)(const std::string_view& ContentTypeString); -const char* ReasonStringForHttpResultCode(int HttpCode); +std::string_view ReasonStringForHttpResultCode(int HttpCode); [[nodiscard]] inline bool IsHttpSuccessCode(int HttpCode) diff --git a/zenserver/upstream/jupiter.cpp b/zenserver/upstream/jupiter.cpp index 6eaa6423b..b93635e76 100644 --- a/zenserver/upstream/jupiter.cpp +++ b/zenserver/upstream/jupiter.cpp @@ -162,6 +162,37 @@ CloudCacheSession::GetRef(std::string_view BucketId, const IoHash& Key, ZenConte } CloudCacheResult +CloudCacheSession::GetBlob(const IoHash& Key) +{ + const CloudCacheAccessToken& AccessToken = GetAccessToken(); + if (!AccessToken.IsValid()) + { + return {.ErrorCode = 401, .Reason = std::string("Invalid access token")}; + } + + ExtendableStringBuilder<256> Uri; + Uri << m_CacheClient->ServiceUrl() << "/api/v1/blobs/" << m_CacheClient->BlobStoreNamespace() << "/" << Key.ToHexString(); + + cpr::Session& Session = m_SessionState->Session; + + Session.SetOption(cpr::Url{Uri.c_str()}); + Session.SetOption(cpr::Header{{"Authorization", AccessToken.Value}, {"Accept", "application/octet-stream"}}); + + cpr::Response Response = Session.Get(); + ZEN_DEBUG("GET {}", Response); + + if (Response.error) + { + return {.ErrorCode = static_cast<int32_t>(Response.error.code), .Reason = Response.error.message}; + } + + const bool Success = Response.status_code == 200; + const IoBuffer Buffer = Success ? IoBufferBuilder::MakeCloneFromMemory(Response.text.data(), Response.text.size()) : IoBuffer(); + + return {.Response = Buffer, .Bytes = Response.downloaded_bytes, .ElapsedSeconds = Response.elapsed, .Success = Success}; +} + +CloudCacheResult CloudCacheSession::GetCompressedBlob(const IoHash& Key) { const CloudCacheAccessToken& AccessToken = GetAccessToken(); @@ -193,6 +224,37 @@ CloudCacheSession::GetCompressedBlob(const IoHash& Key) } CloudCacheResult +CloudCacheSession::GetObject(const IoHash& Key) +{ + const CloudCacheAccessToken& AccessToken = GetAccessToken(); + if (!AccessToken.IsValid()) + { + return {.ErrorCode = 401, .Reason = std::string("Invalid access token")}; + } + + ExtendableStringBuilder<256> Uri; + Uri << m_CacheClient->ServiceUrl() << "/api/v1/objects/" << m_CacheClient->BlobStoreNamespace() << "/" << Key.ToHexString(); + + cpr::Session& Session = m_SessionState->Session; + + Session.SetOption(cpr::Url{Uri.c_str()}); + Session.SetOption(cpr::Header{{"Authorization", AccessToken.Value}, {"Accept", "application/x-ue-cb"}}); + + cpr::Response Response = Session.Get(); + ZEN_DEBUG("GET {}", Response); + + if (Response.error) + { + return {.ErrorCode = static_cast<int32_t>(Response.error.code), .Reason = Response.error.message}; + } + + const bool Success = Response.status_code == 200; + const IoBuffer Buffer = Success ? IoBufferBuilder::MakeCloneFromMemory(Response.text.data(), Response.text.size()) : IoBuffer(); + + return {.Response = Buffer, .Bytes = Response.downloaded_bytes, .ElapsedSeconds = Response.elapsed, .Success = Success}; +} + +CloudCacheResult CloudCacheSession::PutDerivedData(std::string_view BucketId, std::string_view Key, IoBuffer DerivedData) { const CloudCacheAccessToken& AccessToken = GetAccessToken(); @@ -279,6 +341,41 @@ CloudCacheSession::PutRef(std::string_view BucketId, const IoHash& Key, IoBuffer } CloudCacheResult +CloudCacheSession::PutBlob(const IoHash& Key, IoBuffer Blob) +{ + const CloudCacheAccessToken& AccessToken = GetAccessToken(); + if (!AccessToken.IsValid()) + { + return {.ErrorCode = 401, .Reason = std::string("Invalid access token")}; + } + + ExtendableStringBuilder<256> Uri; + Uri << m_CacheClient->ServiceUrl() << "/api/v1/blobs/" << m_CacheClient->BlobStoreNamespace() << "/" << Key.ToHexString(); + + cpr::Session& Session = m_SessionState->Session; + + Session.SetOption(cpr::Url{Uri.c_str()}); + Session.SetOption(cpr::Header{{"Authorization", AccessToken.Value}, {"Content-Type", "application/octet-stream"}}); + Session.SetBody(cpr::Body{(const char*)Blob.Data(), Blob.Size()}); + + cpr::Response Response = Session.Put(); + ZEN_DEBUG("PUT {}", Response); + + if (Response.error) + { + return {.ErrorCode = static_cast<int32_t>(Response.error.code), .Reason = Response.error.message}; + } + else if (!VerifyAccessToken(Response.status_code)) + { + return {.ErrorCode = 401, .Reason = std::string("Invalid access token")}; + } + + return {.Bytes = Response.uploaded_bytes, + .ElapsedSeconds = Response.elapsed, + .Success = (Response.status_code == 200 || Response.status_code == 201)}; +} + +CloudCacheResult CloudCacheSession::PutCompressedBlob(const IoHash& Key, IoBuffer Blob) { const CloudCacheAccessToken& AccessToken = GetAccessToken(); @@ -313,6 +410,167 @@ CloudCacheSession::PutCompressedBlob(const IoHash& Key, IoBuffer Blob) .Success = (Response.status_code == 200 || Response.status_code == 201)}; } +CloudCacheResult +CloudCacheSession::PutObject(const IoHash& Key, IoBuffer Object) +{ + const CloudCacheAccessToken& AccessToken = GetAccessToken(); + if (!AccessToken.IsValid()) + { + return {.ErrorCode = 401, .Reason = std::string("Invalid access token")}; + } + + ExtendableStringBuilder<256> Uri; + Uri << m_CacheClient->ServiceUrl() << "/api/v1/objects/" << m_CacheClient->BlobStoreNamespace() << "/" << Key.ToHexString(); + + cpr::Session& Session = m_SessionState->Session; + + Session.SetOption(cpr::Url{Uri.c_str()}); + Session.SetOption(cpr::Header{{"Authorization", AccessToken.Value}, {"Content-Type", "application/x-ue-cb"}}); + Session.SetBody(cpr::Body{(const char*)Object.Data(), Object.Size()}); + + cpr::Response Response = Session.Put(); + ZEN_DEBUG("PUT {}", Response); + + if (Response.error) + { + return {.ErrorCode = static_cast<int32_t>(Response.error.code), .Reason = Response.error.message}; + } + else if (!VerifyAccessToken(Response.status_code)) + { + return {.ErrorCode = 401, .Reason = std::string("Invalid access token")}; + } + + return {.Bytes = Response.uploaded_bytes, + .ElapsedSeconds = Response.elapsed, + .Success = (Response.status_code == 200 || Response.status_code == 201)}; +} + +CloudCacheResult +CloudCacheSession::RefExists(std::string_view BucketId, const IoHash& Key) +{ + const CloudCacheAccessToken& AccessToken = GetAccessToken(); + if (!AccessToken.IsValid()) + { + return {.ErrorCode = 401, .Reason = std::string("Invalid access token")}; + } + + ExtendableStringBuilder<256> Uri; + Uri << m_CacheClient->ServiceUrl() << "/api/v1/refs/" << m_CacheClient->BlobStoreNamespace() << "/" << BucketId << "/" + << Key.ToHexString(); + + cpr::Session& Session = m_SessionState->Session; + + Session.SetOption(cpr::Url{Uri.c_str()}); + Session.SetOption(cpr::Header{{"Authorization", AccessToken.Value}}); + + cpr::Response Response = Session.Put(); + ZEN_DEBUG("HEAD {}", Response); + + if (Response.error) + { + return {.ErrorCode = static_cast<int32_t>(Response.error.code), .Reason = Response.error.message}; + } + else if (!VerifyAccessToken(Response.status_code)) + { + return {.ErrorCode = 401, .Reason = std::string("Invalid access token")}; + } + + return {.ElapsedSeconds = Response.elapsed, .Success = Response.status_code == 200}; +} + +CloudCacheResult +CloudCacheSession::BlobExists(const IoHash& Key) +{ + const CloudCacheAccessToken& AccessToken = GetAccessToken(); + if (!AccessToken.IsValid()) + { + return {.ErrorCode = 401, .Reason = std::string("Invalid access token")}; + } + + ExtendableStringBuilder<256> Uri; + Uri << m_CacheClient->ServiceUrl() << "/api/v1/blobs/" << m_CacheClient->BlobStoreNamespace() << "/" << Key.ToHexString(); + + cpr::Session& Session = m_SessionState->Session; + + Session.SetOption(cpr::Url{Uri.c_str()}); + + cpr::Response Response = Session.Put(); + ZEN_DEBUG("HEAD {}", Response); + + if (Response.error) + { + return {.ErrorCode = static_cast<int32_t>(Response.error.code), .Reason = Response.error.message}; + } + else if (!VerifyAccessToken(Response.status_code)) + { + return {.ErrorCode = 401, .Reason = std::string("Invalid access token")}; + } + + return {.ElapsedSeconds = Response.elapsed, .Success = Response.status_code == 200}; +} + +CloudCacheResult +CloudCacheSession::CompressedBlobExists(const IoHash& Key) +{ + const CloudCacheAccessToken& AccessToken = GetAccessToken(); + if (!AccessToken.IsValid()) + { + return {.ErrorCode = 401, .Reason = std::string("Invalid access token")}; + } + + ExtendableStringBuilder<256> Uri; + Uri << m_CacheClient->ServiceUrl() << "/api/v1/compressed-blobs/" << m_CacheClient->BlobStoreNamespace() << "/" << Key.ToHexString(); + + cpr::Session& Session = m_SessionState->Session; + + Session.SetOption(cpr::Url{Uri.c_str()}); + + cpr::Response Response = Session.Put(); + ZEN_DEBUG("HEAD {}", Response); + + if (Response.error) + { + return {.ErrorCode = static_cast<int32_t>(Response.error.code), .Reason = Response.error.message}; + } + else if (!VerifyAccessToken(Response.status_code)) + { + return {.ErrorCode = 401, .Reason = std::string("Invalid access token")}; + } + + return {.ElapsedSeconds = Response.elapsed, .Success = Response.status_code == 200}; +} + +CloudCacheResult +CloudCacheSession::ObjectExists(const IoHash& Key) +{ + const CloudCacheAccessToken& AccessToken = GetAccessToken(); + if (!AccessToken.IsValid()) + { + return {.ErrorCode = 401, .Reason = std::string("Invalid access token")}; + } + + ExtendableStringBuilder<256> Uri; + Uri << m_CacheClient->ServiceUrl() << "/api/v1/objects/" << m_CacheClient->BlobStoreNamespace() << "/" << Key.ToHexString(); + + cpr::Session& Session = m_SessionState->Session; + + Session.SetOption(cpr::Url{Uri.c_str()}); + + cpr::Response Response = Session.Put(); + ZEN_DEBUG("HEAD {}", Response); + + if (Response.error) + { + return {.ErrorCode = static_cast<int32_t>(Response.error.code), .Reason = Response.error.message}; + } + else if (!VerifyAccessToken(Response.status_code)) + { + return {.ErrorCode = 401, .Reason = std::string("Invalid access token")}; + } + + return {.ElapsedSeconds = Response.elapsed, .Success = Response.status_code == 200}; +} + std::vector<IoHash> CloudCacheSession::Filter(std::string_view BucketId, const std::vector<IoHash>& ChunkHashes) { diff --git a/zenserver/upstream/jupiter.h b/zenserver/upstream/jupiter.h index 868a7b099..f05e059bd 100644 --- a/zenserver/upstream/jupiter.h +++ b/zenserver/upstream/jupiter.h @@ -51,6 +51,7 @@ struct CloudCacheResult int32_t ErrorCode = {}; std::string Reason; bool Success = false; + bool Exists = false; }; /** @@ -70,12 +71,23 @@ public: CloudCacheResult GetDerivedData(std::string_view BucketId, std::string_view Key); CloudCacheResult GetDerivedData(std::string_view BucketId, const IoHash& Key); CloudCacheResult GetRef(std::string_view BucketId, const IoHash& Key, ZenContentType RefType); + CloudCacheResult GetBlob(const IoHash& Key); CloudCacheResult GetCompressedBlob(const IoHash& Key); + CloudCacheResult GetObject(const IoHash& Key); CloudCacheResult PutDerivedData(std::string_view BucketId, std::string_view Key, IoBuffer DerivedData); CloudCacheResult PutDerivedData(std::string_view BucketId, const IoHash& Key, IoBuffer DerivedData); CloudCacheResult PutRef(std::string_view BucketId, const IoHash& Key, IoBuffer Ref, ZenContentType RefType); + CloudCacheResult PutBlob(const IoHash& Key, IoBuffer Blob); CloudCacheResult PutCompressedBlob(const IoHash& Key, IoBuffer Blob); + CloudCacheResult PutObject(const IoHash& Key, IoBuffer Object); + + CloudCacheResult DerivedDataExists(std::string_view BucketId, std::string_view Key); + CloudCacheResult DerivedDataExists(std::string_view BucketId, const IoHash& Key); + CloudCacheResult RefExists(std::string_view BucketId, const IoHash& Key); + CloudCacheResult BlobExists(const IoHash& Key); + CloudCacheResult CompressedBlobExists(const IoHash& Key); + CloudCacheResult ObjectExists(const IoHash& Key); std::vector<IoHash> Filter(std::string_view BucketId, const std::vector<IoHash>& ChunkHashes); |