From 6ec26c46d694a1d5291790a9c70bec25dce4b513 Mon Sep 17 00:00:00 2001 From: Stefan Boberg Date: Thu, 9 Sep 2021 15:14:08 +0200 Subject: Factored out http server related code into zenhttp module since it feels out of place in zencore --- zencore/httpserver.cpp | 389 ------------------------------------------------- 1 file changed, 389 deletions(-) delete mode 100644 zencore/httpserver.cpp (limited to 'zencore/httpserver.cpp') diff --git a/zencore/httpserver.cpp b/zencore/httpserver.cpp deleted file mode 100644 index 4b6bd1c0a..000000000 --- a/zencore/httpserver.cpp +++ /dev/null @@ -1,389 +0,0 @@ -// Copyright Epic Games, Inc. All Rights Reserved. - -#include - -#include "httpsys.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -namespace zen { - -HttpServerRequest::HttpServerRequest() -{ -} - -HttpServerRequest::~HttpServerRequest() -{ -} - -struct CbPackageHeader -{ - uint32_t HeaderMagic; - uint32_t AttachmentCount; - uint32_t Reserved1; - uint32_t Reserved2; -}; - -static constinit uint32_t kCbPkgMagic = 0xaa77aacc; - -struct CbAttachmentEntry -{ - uint64_t AttachmentSize; - uint32_t Reserved1; - IoHash AttachmentHash; -}; - -void -HttpServerRequest::WriteResponse(HttpResponse HttpResponseCode, CbPackage Data) -{ - const std::span& Attachments = Data.GetAttachments(); - - std::vector ResponseBuffers; - ResponseBuffers.reserve(3 + Attachments.size()); // TODO: may want to use an additional fudge factor here to avoid growing since each - // attachment is likely to consist of several buffers - - uint64_t TotalAttachmentsSize = 0; - - // Fixed size header - - CbPackageHeader Hdr{.HeaderMagic = kCbPkgMagic, .AttachmentCount = gsl::narrow(Attachments.size())}; - - ResponseBuffers.push_back(IoBufferBuilder::MakeCloneFromMemory(&Hdr, sizeof Hdr)); - - // Attachment metadata array - - IoBuffer AttachmentMetadataBuffer = IoBuffer{sizeof(CbAttachmentEntry) * (Attachments.size() + /* root */ 1)}; - - CbAttachmentEntry* AttachmentInfo = reinterpret_cast(AttachmentMetadataBuffer.MutableData()); - - ResponseBuffers.push_back(AttachmentMetadataBuffer); // Attachment metadata - - // Root object - - IoBuffer RootIoBuffer = Data.GetObject().GetBuffer().AsIoBuffer(); - ResponseBuffers.push_back(RootIoBuffer); // Root object - - *AttachmentInfo++ = {.AttachmentSize = RootIoBuffer.Size(), .AttachmentHash = Data.GetObjectHash()}; - - // Attachment payloads - - for (const CbAttachment& Attachment : Attachments) - { - CompressedBuffer AttachmentBuffer = Attachment.AsCompressedBinary(); - CompositeBuffer Compressed = AttachmentBuffer.GetCompressed(); - - *AttachmentInfo++ = {.AttachmentSize = AttachmentBuffer.GetCompressedSize(), - .AttachmentHash = IoHash::FromBLAKE3(AttachmentBuffer.GetRawHash())}; - - for (const SharedBuffer& Segment : Compressed.GetSegments()) - { - ResponseBuffers.push_back(Segment.AsIoBuffer()); - TotalAttachmentsSize += Segment.GetSize(); - } - } - - return WriteResponse(HttpResponseCode, HttpContentType::kCbPackage, ResponseBuffers); -} - -void -HttpServerRequest::WriteResponse(HttpResponse HttpResponseCode, CbObject Data) -{ - SharedBuffer Buf = Data.GetBuffer(); - std::array Buffers{IoBufferBuilder::MakeCloneFromMemory(Buf.GetData(), Buf.GetSize())}; - return WriteResponse(HttpResponseCode, HttpContentType::kCbObject, Buffers); -} - -void -HttpServerRequest::WriteResponse(HttpResponse HttpResponseCode, HttpContentType ContentType, std::string_view ResponseString) -{ - return WriteResponse(HttpResponseCode, ContentType, std::u8string_view{(char8_t*)ResponseString.data(), ResponseString.size()}); -} - -void -HttpServerRequest::WriteResponse(HttpResponse HttpResponseCode, HttpContentType ContentType, IoBuffer Blob) -{ - std::array Buffers{Blob}; - return WriteResponse(HttpResponseCode, 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; - } - - const std::string_view Query{QueryIt, QueryEnd}; - - 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 Parm{ThisQuery.data(), EqIndex}; - ThisQuery.remove_prefix(EqIndex + 1); - - Params.KvPairs.emplace_back(Parm, ThisQuery); - } - - QueryIt += DelimIndex; - } - - return Params; -} - -CbObject -HttpServerRequest::ReadPayloadObject() -{ - IoBuffer Payload = ReadPayload(); - - if (Payload) - { - return LoadCompactBinaryObject(std::move(Payload)); - } - else - { - return {}; - } -} - -CbPackage -HttpServerRequest::ReadPayloadPackage() -{ - // TODO: this should not read into a contiguous buffer! - - IoBuffer Payload = ReadPayload(); - MemoryInStream InStream(Payload); - BinaryReader Reader(InStream); - - if (!Payload) - { - return {}; - } - - CbPackage Package; - - CbPackageHeader Hdr; - Reader.Read(&Hdr, sizeof Hdr); - - if (Hdr.HeaderMagic != kCbPkgMagic) - { - // report error - return {}; - } - - uint32_t ChunkCount = Hdr.AttachmentCount + 1; - - std::unique_ptr AttachmentEntries{new CbAttachmentEntry[ChunkCount]}; - - Reader.Read(AttachmentEntries.get(), sizeof(CbAttachmentEntry) * ChunkCount); - - for (uint32_t i = 0; i < ChunkCount; ++i) - { - const uint64_t AttachmentSize = AttachmentEntries[i].AttachmentSize; - IoBuffer AttachmentBuffer{AttachmentSize}; - Reader.Read(AttachmentBuffer.MutableData(), AttachmentSize); - CompressedBuffer CompBuf(CompressedBuffer::FromCompressed(SharedBuffer(AttachmentBuffer))); - - if (i == 0) - { - Package.SetObject(LoadCompactBinaryObject(CompBuf)); - } - else - { - CbAttachment Attachment(CompBuf); - Package.AddAttachment(Attachment); - } - } - - return Package; -} - -////////////////////////////////////////////////////////////////////////// - -HttpServerException::HttpServerException(const char* Message, uint32_t Error) : m_ErrorCode(Error) -{ - using namespace fmt::literals; - - m_Message = "{} (HTTP error {})"_format(Message, m_ErrorCode); -} - -const char* -HttpServerException::what() const -{ - return m_Message.c_str(); -} - -////////////////////////////////////////////////////////////////////////// - -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::RegisterRoute(const char* Regex, PackageEndpointHandler& Handler) -{ - ExtendableStringBuilder<128> ExpandedRegex; - ProcessRegexSubstitutions(Regex, ExpandedRegex); - - m_Handlers.emplace_back( - ExpandedRegex.c_str(), - HttpVerb::kPost, - [&Handler](HttpRouterRequest& Request) { Handler.HandleRequest(Request); }, - 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 -} - -////////////////////////////////////////////////////////////////////////// - -Ref -CreateHttpServer() -{ - return new HttpSysServer{32}; -} - -////////////////////////////////////////////////////////////////////////// - -TEST_CASE("http") -{ - 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); - } -} - -void -http_forcelink() -{ -} - -} // namespace zen -- cgit v1.2.3