aboutsummaryrefslogtreecommitdiff
path: root/zenhttp/httpserver.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'zenhttp/httpserver.cpp')
-rw-r--r--zenhttp/httpserver.cpp885
1 files changed, 0 insertions, 885 deletions
diff --git a/zenhttp/httpserver.cpp b/zenhttp/httpserver.cpp
deleted file mode 100644
index 671cbd319..000000000
--- a/zenhttp/httpserver.cpp
+++ /dev/null
@@ -1,885 +0,0 @@
-// Copyright Epic Games, Inc. All Rights Reserved.
-
-#include <zenhttp/httpserver.h>
-
-#include "httpasio.h"
-#include "httpnull.h"
-#include "httpsys.h"
-
-#include <zencore/compactbinary.h>
-#include <zencore/compactbinarybuilder.h>
-#include <zencore/compactbinarypackage.h>
-#include <zencore/iobuffer.h>
-#include <zencore/logging.h>
-#include <zencore/refcount.h>
-#include <zencore/stream.h>
-#include <zencore/string.h>
-#include <zencore/testing.h>
-#include <zencore/thread.h>
-#include <zenhttp/httpshared.h>
-
-#include <charconv>
-#include <mutex>
-#include <span>
-#include <string_view>
-
-namespace zen {
-
-using namespace std::literals;
-
-std::string_view
-MapContentTypeToString(HttpContentType ContentType)
-{
- switch (ContentType)
- {
- default:
- case HttpContentType::kUnknownContentType:
- case HttpContentType::kBinary:
- return "application/octet-stream"sv;
-
- case HttpContentType::kText:
- return "text/plain"sv;
-
- case HttpContentType::kJSON:
- return "application/json"sv;
-
- case HttpContentType::kCbObject:
- return "application/x-ue-cb"sv;
-
- case HttpContentType::kCbPackage:
- return "application/x-ue-cbpkg"sv;
-
- case HttpContentType::kCbPackageOffer:
- return "application/x-ue-offer"sv;
-
- case HttpContentType::kCompressedBinary:
- return "application/x-ue-comp"sv;
-
- case HttpContentType::kYAML:
- return "text/yaml"sv;
-
- case HttpContentType::kHTML:
- return "text/html"sv;
-
- case HttpContentType::kJavaScript:
- return "application/javascript"sv;
-
- case HttpContentType::kCSS:
- return "text/css"sv;
-
- case HttpContentType::kPNG:
- return "image/png"sv;
-
- case HttpContentType::kIcon:
- return "image/x-icon"sv;
- }
-}
-
-//////////////////////////////////////////////////////////////////////////
-//
-// Note that in addition to MIME types we accept abbreviated versions, for
-// use in suffix parsing as well as for convenience when using curl
-
-static constinit uint32_t HashBinary = HashStringDjb2("application/octet-stream"sv);
-static constinit uint32_t HashJson = HashStringDjb2("json"sv);
-static constinit uint32_t HashApplicationJson = HashStringDjb2("application/json"sv);
-static constinit uint32_t HashYaml = HashStringDjb2("yaml"sv);
-static constinit uint32_t HashTextYaml = HashStringDjb2("text/yaml"sv);
-static constinit uint32_t HashText = HashStringDjb2("text/plain"sv);
-static constinit uint32_t HashApplicationCompactBinary = HashStringDjb2("application/x-ue-cb"sv);
-static constinit uint32_t HashCompactBinary = HashStringDjb2("ucb"sv);
-static constinit uint32_t HashCompactBinaryPackage = HashStringDjb2("application/x-ue-cbpkg"sv);
-static constinit uint32_t HashCompactBinaryPackageShort = HashStringDjb2("cbpkg"sv);
-static constinit uint32_t HashCompactBinaryPackageOffer = HashStringDjb2("application/x-ue-offer"sv);
-static constinit uint32_t HashCompressedBinary = HashStringDjb2("application/x-ue-comp"sv);
-static constinit uint32_t HashHtml = HashStringDjb2("html"sv);
-static constinit uint32_t HashTextHtml = HashStringDjb2("text/html"sv);
-static constinit uint32_t HashJavaScript = HashStringDjb2("js"sv);
-static constinit uint32_t HashApplicationJavaScript = HashStringDjb2("application/javascript"sv);
-static constinit uint32_t HashCss = HashStringDjb2("css"sv);
-static constinit uint32_t HashTextCss = HashStringDjb2("text/css"sv);
-static constinit uint32_t HashPng = HashStringDjb2("png"sv);
-static constinit uint32_t HashImagePng = HashStringDjb2("image/png"sv);
-static constinit uint32_t HashIcon = HashStringDjb2("ico"sv);
-static constinit uint32_t HashImageIcon = HashStringDjb2("image/x-icon"sv);
-
-std::once_flag InitContentTypeLookup;
-
-struct HashedTypeEntry
-{
- uint32_t Hash;
- HttpContentType Type;
-} TypeHashTable[] = {
- // clang-format off
- {HashBinary, HttpContentType::kBinary},
- {HashApplicationCompactBinary, HttpContentType::kCbObject},
- {HashCompactBinary, HttpContentType::kCbObject},
- {HashCompactBinaryPackage, HttpContentType::kCbPackage},
- {HashCompactBinaryPackageShort, HttpContentType::kCbPackage},
- {HashCompactBinaryPackageOffer, HttpContentType::kCbPackageOffer},
- {HashJson, HttpContentType::kJSON},
- {HashApplicationJson, HttpContentType::kJSON},
- {HashYaml, HttpContentType::kYAML},
- {HashTextYaml, HttpContentType::kYAML},
- {HashText, HttpContentType::kText},
- {HashCompressedBinary, HttpContentType::kCompressedBinary},
- {HashHtml, HttpContentType::kHTML},
- {HashTextHtml, HttpContentType::kHTML},
- {HashJavaScript, HttpContentType::kJavaScript},
- {HashApplicationJavaScript, HttpContentType::kJavaScript},
- {HashCss, HttpContentType::kCSS},
- {HashTextCss, HttpContentType::kCSS},
- {HashPng, HttpContentType::kPNG},
- {HashImagePng, HttpContentType::kPNG},
- {HashIcon, HttpContentType::kIcon},
- {HashImageIcon, HttpContentType::kIcon},
- // clang-format on
-};
-
-HttpContentType
-ParseContentTypeImpl(const std::string_view& ContentTypeString)
-{
- if (!ContentTypeString.empty())
- {
- const uint32_t CtHash = HashStringDjb2(ContentTypeString);
-
- if (auto It = std::lower_bound(std::begin(TypeHashTable),
- std::end(TypeHashTable),
- CtHash,
- [](const HashedTypeEntry& Lhs, const uint32_t Rhs) { return Lhs.Hash < Rhs; });
- It != std::end(TypeHashTable))
- {
- if (It->Hash == CtHash)
- {
- return It->Type;
- }
- }
- }
-
- return HttpContentType::kUnknownContentType;
-}
-
-HttpContentType
-ParseContentTypeInit(const std::string_view& ContentTypeString)
-{
- std::call_once(InitContentTypeLookup, [] {
- std::sort(std::begin(TypeHashTable), std::end(TypeHashTable), [](const HashedTypeEntry& Lhs, const HashedTypeEntry& Rhs) {
- return Lhs.Hash < Rhs.Hash;
- });
-
- // validate that there are no hash collisions
-
- uint32_t LastHash = 0;
-
- for (const auto& Item : TypeHashTable)
- {
- ZEN_ASSERT(LastHash != Item.Hash);
- LastHash = Item.Hash;
- }
- });
-
- ParseContentType = ParseContentTypeImpl;
-
- return ParseContentTypeImpl(ContentTypeString);
-}
-
-HttpContentType (*ParseContentType)(const std::string_view& ContentTypeString) = &ParseContentTypeInit;
-
-bool
-TryParseHttpRangeHeader(std::string_view RangeHeader, HttpRanges& Ranges)
-{
- if (RangeHeader.empty())
- {
- return false;
- }
-
- const size_t Count = Ranges.size();
-
- std::size_t UnitDelim = RangeHeader.find_first_of('=');
- if (UnitDelim == std::string_view::npos)
- {
- return false;
- }
-
- // only bytes for now
- std::string_view Unit = RangeHeader.substr(0, UnitDelim);
- if (Unit != "bytes"sv)
- {
- return false;
- }
-
- std::string_view Tokens = RangeHeader.substr(UnitDelim);
- while (!Tokens.empty())
- {
- // Skip =,
- Tokens = Tokens.substr(1);
-
- size_t Delim = Tokens.find_first_of(',');
- if (Delim == std::string_view::npos)
- {
- Delim = Tokens.length();
- }
-
- std::string_view Token = Tokens.substr(0, Delim);
- Tokens = Tokens.substr(Delim);
-
- Delim = Token.find_first_of('-');
- if (Delim == std::string_view::npos)
- {
- return false;
- }
-
- const auto Start = ParseInt<uint32_t>(Token.substr(0, Delim));
- const auto End = ParseInt<uint32_t>(Token.substr(Delim + 1));
-
- if (Start.has_value() && End.has_value() && End.value() > Start.value())
- {
- Ranges.push_back({.Start = Start.value(), .End = End.value()});
- }
- else if (Start)
- {
- Ranges.push_back({.Start = Start.value()});
- }
- else if (End)
- {
- Ranges.push_back({.End = End.value()});
- }
- }
-
- return Count != Ranges.size();
-}
-
-//////////////////////////////////////////////////////////////////////////
-
-const std::string_view
-ToString(HttpVerb Verb)
-{
- switch (Verb)
- {
- case HttpVerb::kGet:
- return "GET"sv;
- case HttpVerb::kPut:
- return "PUT"sv;
- case HttpVerb::kPost:
- return "POST"sv;
- case HttpVerb::kDelete:
- return "DELETE"sv;
- case HttpVerb::kHead:
- return "HEAD"sv;
- case HttpVerb::kCopy:
- return "COPY"sv;
- case HttpVerb::kOptions:
- return "OPTIONS"sv;
- default:
- return "???"sv;
- }
-}
-
-std::string_view
-ReasonStringForHttpResultCode(int HttpCode)
-{
- switch (HttpCode)
- {
- // 1xx Informational
-
- case 100:
- return "Continue"sv;
- case 101:
- return "Switching Protocols"sv;
-
- // 2xx Success
-
- case 200:
- return "OK"sv;
- case 201:
- return "Created"sv;
- case 202:
- return "Accepted"sv;
- case 204:
- return "No Content"sv;
- case 205:
- return "Reset Content"sv;
- case 206:
- return "Partial Content"sv;
-
- // 3xx Redirection
-
- case 300:
- return "Multiple Choices"sv;
- case 301:
- return "Moved Permanently"sv;
- case 302:
- return "Found"sv;
- case 303:
- return "See Other"sv;
- case 304:
- return "Not Modified"sv;
- case 305:
- return "Use Proxy"sv;
- case 306:
- return "Switch Proxy"sv;
- case 307:
- return "Temporary Redirect"sv;
- case 308:
- return "Permanent Redirect"sv;
-
- // 4xx Client errors
-
- case 400:
- return "Bad Request"sv;
- case 401:
- return "Unauthorized"sv;
- case 402:
- return "Payment Required"sv;
- case 403:
- return "Forbidden"sv;
- case 404:
- return "Not Found"sv;
- case 405:
- return "Method Not Allowed"sv;
- case 406:
- return "Not Acceptable"sv;
- case 407:
- return "Proxy Authentication Required"sv;
- case 408:
- return "Request Timeout"sv;
- case 409:
- return "Conflict"sv;
- case 410:
- return "Gone"sv;
- case 411:
- return "Length Required"sv;
- case 412:
- return "Precondition Failed"sv;
- case 413:
- return "Payload Too Large"sv;
- case 414:
- return "URI Too Long"sv;
- case 415:
- return "Unsupported Media Type"sv;
- case 416:
- return "Range Not Satisifiable"sv;
- case 417:
- return "Expectation Failed"sv;
- case 418:
- return "I'm a teapot"sv;
- case 421:
- return "Misdirected Request"sv;
- case 422:
- return "Unprocessable Entity"sv;
- case 423:
- return "Locked"sv;
- case 424:
- return "Failed Dependency"sv;
- case 425:
- return "Too Early"sv;
- case 426:
- return "Upgrade Required"sv;
- case 428:
- return "Precondition Required"sv;
- case 429:
- return "Too Many Requests"sv;
- case 431:
- return "Request Header Fields Too Large"sv;
-
- // 5xx Server errors
-
- case 500:
- return "Internal Server Error"sv;
- case 501:
- return "Not Implemented"sv;
- case 502:
- return "Bad Gateway"sv;
- case 503:
- return "Service Unavailable"sv;
- case 504:
- return "Gateway Timeout"sv;
- case 505:
- return "HTTP Version Not Supported"sv;
- case 506:
- return "Variant Also Negotiates"sv;
- case 507:
- return "Insufficient Storage"sv;
- case 508:
- return "Loop Detected"sv;
- case 510:
- return "Not Extended"sv;
- case 511:
- return "Network Authentication Required"sv;
-
- default:
- return "Unknown Result"sv;
- }
-}
-
-//////////////////////////////////////////////////////////////////////////
-
-Ref<IHttpPackageHandler>
-HttpService::HandlePackageRequest(HttpServerRequest& HttpServiceRequest)
-{
- ZEN_UNUSED(HttpServiceRequest);
-
- return Ref<IHttpPackageHandler>();
-}
-
-//////////////////////////////////////////////////////////////////////////
-
-HttpServerRequest::HttpServerRequest()
-{
-}
-
-HttpServerRequest::~HttpServerRequest()
-{
-}
-
-void
-HttpServerRequest::WriteResponse(HttpResponseCode ResponseCode, CbPackage Data)
-{
- std::vector<IoBuffer> ResponseBuffers = FormatPackageMessage(Data);
- return WriteResponse(ResponseCode, HttpContentType::kCbPackage, ResponseBuffers);
-}
-
-void
-HttpServerRequest::WriteResponse(HttpResponseCode ResponseCode, CbObject Data)
-{
- if (m_AcceptType == HttpContentType::kJSON)
- {
- ExtendableStringBuilder<1024> Sb;
- WriteResponse(ResponseCode, HttpContentType::kJSON, Data.ToJson(Sb).ToView());
- }
- else
- {
- SharedBuffer Buf = Data.GetBuffer();
- std::array<IoBuffer, 1> Buffers{IoBufferBuilder::MakeCloneFromMemory(Buf.GetData(), Buf.GetSize())};
- return WriteResponse(ResponseCode, HttpContentType::kCbObject, Buffers);
- }
-}
-
-void
-HttpServerRequest::WriteResponse(HttpResponseCode ResponseCode, CbArray Array)
-{
- if (m_AcceptType == HttpContentType::kJSON)
- {
- ExtendableStringBuilder<1024> Sb;
- WriteResponse(ResponseCode, HttpContentType::kJSON, Array.ToJson(Sb).ToView());
- }
- else
- {
- SharedBuffer Buf = Array.GetBuffer();
- std::array<IoBuffer, 1> Buffers{IoBufferBuilder::MakeCloneFromMemory(Buf.GetData(), Buf.GetSize())};
- return WriteResponse(ResponseCode, HttpContentType::kCbObject, Buffers);
- }
-}
-
-void
-HttpServerRequest::WriteResponse(HttpResponseCode ResponseCode, HttpContentType ContentType, std::string_view ResponseString)
-{
- return WriteResponse(ResponseCode, ContentType, std::u8string_view{(char8_t*)ResponseString.data(), ResponseString.size()});
-}
-
-void
-HttpServerRequest::WriteResponse(HttpResponseCode ResponseCode, HttpContentType ContentType, IoBuffer Blob)
-{
- std::array<IoBuffer, 1> Buffers{Blob};
- return WriteResponse(ResponseCode, ContentType, Buffers);
-}
-
-void
-HttpServerRequest::WriteResponse(HttpResponseCode ResponseCode, HttpContentType ContentType, CompositeBuffer& Payload)
-{
- std::span<const SharedBuffer> Segments = Payload.GetSegments();
-
- std::vector<IoBuffer> Buffers;
-
- for (auto& Segment : Segments)
- {
- Buffers.push_back(Segment.AsIoBuffer());
- }
-
- WriteResponse(ResponseCode, ContentType, Buffers);
-}
-
-HttpServerRequest::QueryParams
-HttpServerRequest::GetQueryParams()
-{
- QueryParams Params;
-
- const std::string_view QStr = QueryString();
-
- const char* QueryIt = QStr.data();
- const char* QueryEnd = QueryIt + QStr.size();
-
- while (QueryIt != QueryEnd)
- {
- if (*QueryIt == '&')
- {
- ++QueryIt;
- continue;
- }
-
- size_t QueryLen = ptrdiff_t(QueryEnd - QueryIt);
- const std::string_view Query{QueryIt, QueryLen};
-
- size_t DelimIndex = Query.find('&', 0);
-
- if (DelimIndex == std::string_view::npos)
- {
- DelimIndex = Query.size();
- }
-
- std::string_view ThisQuery{QueryIt, DelimIndex};
-
- size_t EqIndex = ThisQuery.find('=', 0);
-
- if (EqIndex != std::string_view::npos)
- {
- std::string_view Param{ThisQuery.data(), EqIndex};
- ThisQuery.remove_prefix(EqIndex + 1);
-
- Params.KvPairs.emplace_back(Param, ThisQuery);
- }
-
- QueryIt += DelimIndex;
- }
-
- return Params;
-}
-
-Oid
-HttpServerRequest::SessionId() const
-{
- if (m_Flags & kHaveSessionId)
- {
- return m_SessionId;
- }
-
- m_SessionId = ParseSessionId();
- m_Flags |= kHaveSessionId;
- return m_SessionId;
-}
-
-uint32_t
-HttpServerRequest::RequestId() const
-{
- if (m_Flags & kHaveRequestId)
- {
- return m_RequestId;
- }
-
- m_RequestId = ParseRequestId();
- m_Flags |= kHaveRequestId;
- return m_RequestId;
-}
-
-CbObject
-HttpServerRequest::ReadPayloadObject()
-{
- if (IoBuffer Payload = ReadPayload())
- {
- return LoadCompactBinaryObject(std::move(Payload));
- }
-
- return {};
-}
-
-CbPackage
-HttpServerRequest::ReadPayloadPackage()
-{
- if (IoBuffer Payload = ReadPayload())
- {
- return ParsePackageMessage(std::move(Payload));
- }
-
- return {};
-}
-
-//////////////////////////////////////////////////////////////////////////
-
-void
-HttpRequestRouter::AddPattern(const char* Id, const char* Regex)
-{
- ZEN_ASSERT(m_PatternMap.find(Id) == m_PatternMap.end());
-
- m_PatternMap.insert({Id, Regex});
-}
-
-void
-HttpRequestRouter::RegisterRoute(const char* Regex, HttpRequestRouter::HandlerFunc_t&& HandlerFunc, HttpVerb SupportedVerbs)
-{
- ExtendableStringBuilder<128> ExpandedRegex;
- ProcessRegexSubstitutions(Regex, ExpandedRegex);
-
- m_Handlers.emplace_back(ExpandedRegex.c_str(), SupportedVerbs, std::move(HandlerFunc), Regex);
-}
-
-void
-HttpRequestRouter::ProcessRegexSubstitutions(const char* Regex, StringBuilderBase& OutExpandedRegex)
-{
- size_t RegexLen = strlen(Regex);
-
- for (size_t i = 0; i < RegexLen;)
- {
- bool matched = false;
-
- if (Regex[i] == '{' && ((i == 0) || (Regex[i - 1] != '\\')))
- {
- // Might have a pattern reference - find closing brace
-
- for (size_t j = i + 1; j < RegexLen; ++j)
- {
- if (Regex[j] == '}')
- {
- std::string Pattern(&Regex[i + 1], j - i - 1);
-
- if (auto it = m_PatternMap.find(Pattern); it != m_PatternMap.end())
- {
- OutExpandedRegex.Append(it->second.c_str());
- }
- else
- {
- // Default to anything goes (or should this just be an error?)
-
- OutExpandedRegex.Append("(.+?)");
- }
-
- // skip ahead
- i = j + 1;
-
- matched = true;
-
- break;
- }
- }
- }
-
- if (!matched)
- {
- OutExpandedRegex.Append(Regex[i++]);
- }
- }
-}
-
-bool
-HttpRequestRouter::HandleRequest(zen::HttpServerRequest& Request)
-{
- const HttpVerb Verb = Request.RequestVerb();
-
- std::string_view Uri = Request.RelativeUri();
- HttpRouterRequest RouterRequest(Request);
-
- for (const auto& Handler : m_Handlers)
- {
- if ((Handler.Verbs & Verb) == Verb && regex_match(begin(Uri), end(Uri), RouterRequest.m_Match, Handler.RegEx))
- {
- Handler.Handler(RouterRequest);
-
- return true; // Route matched
- }
- }
-
- return false; // No route matched
-}
-
-//////////////////////////////////////////////////////////////////////////
-
-HttpRpcHandler::HttpRpcHandler()
-{
-}
-
-HttpRpcHandler::~HttpRpcHandler()
-{
-}
-
-void
-HttpRpcHandler::AddRpc(std::string_view RpcId, std::function<void(CbObject& RpcArgs)> HandlerFunction)
-{
- ZEN_UNUSED(RpcId, HandlerFunction);
-}
-
-//////////////////////////////////////////////////////////////////////////
-
-enum class HttpServerClass
-{
- kHttpAsio,
- kHttpSys,
- kHttpNull
-};
-
-// Implemented in httpsys.cpp
-Ref<HttpServer> CreateHttpSysServer(int Concurrency, int BackgroundWorkerThreads);
-
-Ref<HttpServer>
-CreateHttpServer(std::string_view ServerClass)
-{
- using namespace std::literals;
-
- HttpServerClass Class = HttpServerClass::kHttpNull;
-
-#if ZEN_WITH_HTTPSYS
- Class = HttpServerClass::kHttpSys;
-#elif 1
- Class = HttpServerClass::kHttpAsio;
-#endif
-
- if (ServerClass == "asio"sv)
- {
- Class = HttpServerClass::kHttpAsio;
- }
- else if (ServerClass == "httpsys"sv)
- {
- Class = HttpServerClass::kHttpSys;
- }
- else if (ServerClass == "null"sv)
- {
- Class = HttpServerClass::kHttpNull;
- }
-
- switch (Class)
- {
- default:
- case HttpServerClass::kHttpAsio:
- ZEN_INFO("using asio HTTP server implementation");
- return Ref<HttpServer>(new HttpAsioServer());
-
-#if ZEN_WITH_HTTPSYS
- case HttpServerClass::kHttpSys:
- ZEN_INFO("using http.sys server implementation");
- return Ref<HttpServer>(new HttpSysServer(std::thread::hardware_concurrency(), /* background worker threads */ 16));
-#endif
-
- case HttpServerClass::kHttpNull:
- ZEN_INFO("using null HTTP server implementation");
- return Ref<HttpServer>(new HttpNullServer);
- }
-}
-
-//////////////////////////////////////////////////////////////////////////
-
-bool
-HandlePackageOffers(HttpService& Service, HttpServerRequest& Request, Ref<IHttpPackageHandler>& PackageHandlerRef)
-{
- if (Request.RequestVerb() == HttpVerb::kPost)
- {
- if (Request.RequestContentType() == HttpContentType::kCbPackageOffer)
- {
- // The client is presenting us with a package attachments offer, we need
- // to filter it down to the list of attachments we need them to send in
- // the follow-up request
-
- PackageHandlerRef = Service.HandlePackageRequest(Request);
-
- if (PackageHandlerRef)
- {
- CbObject OfferMessage = LoadCompactBinaryObject(Request.ReadPayload());
-
- std::vector<IoHash> OfferCids;
-
- for (auto& CidEntry : OfferMessage["offer"])
- {
- if (!CidEntry.IsHash())
- {
- // Should yield bad request response?
-
- ZEN_WARN("found invalid entry in offer");
-
- continue;
- }
-
- OfferCids.push_back(CidEntry.AsHash());
- }
-
- ZEN_TRACE("request #{} -> filtering offer of {} entries", Request.RequestId(), OfferCids.size());
-
- PackageHandlerRef->FilterOffer(OfferCids);
-
- ZEN_TRACE("request #{} -> filtered to {} entries", Request.RequestId(), OfferCids.size());
-
- CbObjectWriter ResponseWriter;
- ResponseWriter.BeginArray("need");
-
- for (const IoHash& Cid : OfferCids)
- {
- ResponseWriter.AddHash(Cid);
- }
-
- ResponseWriter.EndArray();
-
- // Emit filter response
- Request.WriteResponse(HttpResponseCode::OK, ResponseWriter.Save());
- return true;
- }
- }
- else if (Request.RequestContentType() == HttpContentType::kCbPackage)
- {
- // Process chunks in package request
-
- PackageHandlerRef = Service.HandlePackageRequest(Request);
-
- // TODO: this should really be done in a streaming fashion, currently this emulates
- // the intended flow from an API perspective
-
- if (PackageHandlerRef)
- {
- PackageHandlerRef->OnRequestBegin();
-
- auto CreateBuffer = [&](const IoHash& Cid, uint64_t Size) -> IoBuffer {
- return PackageHandlerRef->CreateTarget(Cid, Size);
- };
-
- CbPackage Package = ParsePackageMessage(Request.ReadPayload(), CreateBuffer);
-
- PackageHandlerRef->OnRequestComplete();
- }
- }
- }
- return false;
-}
-
-//////////////////////////////////////////////////////////////////////////
-
-#if ZEN_WITH_TESTS
-
-TEST_CASE("http.common")
-{
- using namespace std::literals;
-
- SUBCASE("router")
- {
- HttpRequestRouter r;
- r.AddPattern("a", "[[:alpha:]]+");
- r.RegisterRoute(
- "{a}",
- [&](auto) {},
- HttpVerb::kGet);
-
- // struct TestHttpServerRequest : public HttpServerRequest
- //{
- // TestHttpServerRequest(std::string_view Uri) : m_uri{Uri} {}
- //};
-
- // TestHttpServerRequest req{};
- // r.HandleRequest(req);
- }
-
- SUBCASE("content-type")
- {
- for (uint8_t i = 0; i < uint8_t(HttpContentType::kCOUNT); ++i)
- {
- HttpContentType Ct{i};
-
- if (Ct != HttpContentType::kUnknownContentType)
- {
- CHECK_EQ(Ct, ParseContentType(MapContentTypeToString(Ct)));
- }
- }
- }
-}
-
-void
-http_forcelink()
-{
-}
-
-#endif
-
-} // namespace zen