diff options
| author | Stefan Boberg <[email protected]> | 2021-09-09 15:14:08 +0200 |
|---|---|---|
| committer | Stefan Boberg <[email protected]> | 2021-09-09 15:14:08 +0200 |
| commit | 6ec26c46d694a1d5291790a9c70bec25dce4b513 (patch) | |
| tree | 4177d45f9703d11f00e495f0fde77f4445453d2d /zencore | |
| parent | HttpServer::AddEndpoint -> HttpServer::RegisterService (diff) | |
| download | zen-6ec26c46d694a1d5291790a9c70bec25dce4b513.tar.xz zen-6ec26c46d694a1d5291790a9c70bec25dce4b513.zip | |
Factored out http server related code into zenhttp module since it feels out of place in zencore
Diffstat (limited to 'zencore')
| -rw-r--r-- | zencore/httpclient.cpp | 23 | ||||
| -rw-r--r-- | zencore/httpserver.cpp | 389 | ||||
| -rw-r--r-- | zencore/httpsys.cpp | 1250 | ||||
| -rw-r--r-- | zencore/httpsys.h | 61 | ||||
| -rw-r--r-- | zencore/include/zencore/httpclient.h | 22 | ||||
| -rw-r--r-- | zencore/include/zencore/httpserver.h | 446 | ||||
| -rw-r--r-- | zencore/iothreadpool.cpp | 36 | ||||
| -rw-r--r-- | zencore/iothreadpool.h | 31 | ||||
| -rw-r--r-- | zencore/zencore.vcxproj | 8 | ||||
| -rw-r--r-- | zencore/zencore.vcxproj.filters | 8 |
10 files changed, 0 insertions, 2274 deletions
diff --git a/zencore/httpclient.cpp b/zencore/httpclient.cpp deleted file mode 100644 index 268483403..000000000 --- a/zencore/httpclient.cpp +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright Epic Games, Inc. All Rights Reserved. - -#include <zencore/httpclient.h> - -#include <spdlog/spdlog.h> - -#include <doctest/doctest.h> - -namespace zen { - -TEST_CASE("httpclient") -{ - using namespace std::literals; - - SUBCASE("client") {} -} - -void -httpclient_forcelink() -{ -} - -} // namespace zen 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 <zencore/httpserver.h> - -#include "httpsys.h" - -#include <zencore/compactbinary.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/thread.h> - -#include <conio.h> -#include <new.h> -#include <charconv> -#include <span> -#include <string_view> - -#include <doctest/doctest.h> - -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<const CbAttachment>& Attachments = Data.GetAttachments(); - - std::vector<IoBuffer> 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<uint32_t>(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<CbAttachmentEntry*>(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<IoBuffer, 1> 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<IoBuffer, 1> 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<CbAttachmentEntry[]> 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<HttpServer> -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 diff --git a/zencore/httpsys.cpp b/zencore/httpsys.cpp deleted file mode 100644 index da07a13dd..000000000 --- a/zencore/httpsys.cpp +++ /dev/null @@ -1,1250 +0,0 @@ -// Copyright Epic Games, Inc. All Rights Reserved. - -#include "httpsys.h" - -#include <zencore/logging.h> -#include <zencore/string.h> - -#include <conio.h> - -#if ZEN_PLATFORM_WINDOWS -# pragma comment(lib, "httpapi.lib") -#endif - -std::wstring -UTF8_to_wstring(const char* in) -{ - std::wstring out; - unsigned int codepoint; - - while (*in != 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; - else - codepoint = ch & 0x07; - - ++in; - - if (((*in & 0xc0) != 0x80) && (codepoint <= 0x10ffff)) - { - if (sizeof(wchar_t) > 2) - { - out.append(1, static_cast<wchar_t>(codepoint)); - } - else if (codepoint > 0xffff) - { - 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)); - } - } - } - - return out; -} - -////////////////////////////////////////////////////////////////////////// -// -// http.sys implementation -// - -namespace zen { - -using namespace std::literals; - -static const uint32_t HashBinary = HashStringDjb2("application/octet-stream"sv); -static const uint32_t HashJson = HashStringDjb2("application/json"sv); -static const uint32_t HashYaml = HashStringDjb2("text/yaml"sv); -static const uint32_t HashText = HashStringDjb2("text/plain"sv); -static const uint32_t HashCompactBinary = HashStringDjb2("application/x-ue-cb"sv); -static const uint32_t HashCompactBinaryPackage = HashStringDjb2("application/x-ue-cbpkg"sv); - -HttpContentType -MapContentType(const std::string_view& ContentTypeString) -{ - if (!ContentTypeString.empty()) - { - const uint32_t CtHash = HashStringDjb2(ContentTypeString); - - if (CtHash == HashBinary) - { - return HttpContentType::kBinary; - } - else if (CtHash == HashCompactBinary) - { - return HttpContentType::kCbObject; - } - else if (CtHash == HashCompactBinaryPackage) - { - return HttpContentType::kCbPackage; - } - else if (CtHash == HashJson) - { - return HttpContentType::kJSON; - } - else if (CtHash == HashYaml) - { - return HttpContentType::kYAML; - } - else if (CtHash == HashText) - { - return HttpContentType::kText; - } - } - - return HttpContentType::kUnknownContentType; -} - -////////////////////////////////////////////////////////////////////////// - -const char* -ReasonStringForHttpResultCode(int HttpCode) -{ - switch (HttpCode) - { - // 1xx Informational - - case 100: - return "Continue"; - case 101: - return "Switching Protocols"; - - // 2xx Success - - case 200: - return "OK"; - case 201: - return "Created"; - case 202: - return "Accepted"; - case 204: - return "No Content"; - case 205: - return "Reset Content"; - case 206: - return "Partial Content"; - - // 3xx Redirection - - case 300: - return "Multiple Choices"; - case 301: - return "Moved Permanently"; - case 302: - return "Found"; - case 303: - return "See Other"; - case 304: - return "Not Modified"; - case 305: - return "Use Proxy"; - case 306: - return "Switch Proxy"; - case 307: - return "Temporary Redirect"; - case 308: - return "Permanent Redirect"; - - // 4xx Client errors - - case 400: - return "Bad Request"; - case 401: - return "Unauthorized"; - case 402: - return "Payment Required"; - case 403: - return "Forbidden"; - case 404: - return "Not Found"; - case 405: - return "Method Not Allowed"; - case 406: - return "Not Acceptable"; - case 407: - return "Proxy Authentication Required"; - case 408: - return "Request Timeout"; - case 409: - return "Conflict"; - case 410: - return "Gone"; - case 411: - return "Length Required"; - case 412: - return "Precondition Failed"; - case 413: - return "Payload Too Large"; - case 414: - return "URI Too Long"; - case 415: - return "Unsupported Media Type"; - case 416: - return "Range Not Satisifiable"; - case 417: - return "Expectation Failed"; - case 418: - return "I'm a teapot"; - case 421: - return "Misdirected Request"; - case 422: - return "Unprocessable Entity"; - case 423: - return "Locked"; - case 424: - return "Failed Dependency"; - case 425: - return "Too Early"; - case 426: - return "Upgrade Required"; - case 428: - return "Precondition Required"; - case 429: - return "Too Many Requests"; - case 431: - return "Request Header Fields Too Large"; - - // 5xx Server errors - - case 500: - return "Internal Server Error"; - case 501: - return "Not Implemented"; - case 502: - return "Bad Gateway"; - case 503: - return "Service Unavailable"; - case 504: - return "Gateway Timeout"; - case 505: - return "HTTP Version Not Supported"; - case 506: - return "Variant Also Negotiates"; - case 507: - return "Insufficient Storage"; - case 508: - return "Loop Detected"; - case 510: - return "Not Extended"; - case 511: - return "Network Authentication Required"; - - default: - return "Unknown Result"; - } -} - -#if ZEN_PLATFORM_WINDOWS -class HttpSysServer; -class HttpSysTransaction; -class HttpMessageResponseRequest; - -class HttpSysRequestHandler -{ -public: - HttpSysRequestHandler(HttpSysTransaction& InRequest) : m_Request(InRequest) {} - virtual ~HttpSysRequestHandler() = default; - - virtual void IssueRequest() = 0; - virtual HttpSysRequestHandler* HandleCompletion(ULONG IoResult, ULONG_PTR NumberOfBytesTransferred) = 0; - - HttpSysTransaction& Transaction() { return m_Request; } - -private: - HttpSysTransaction& m_Request; // Outermost HTTP transaction object -}; - -struct InitialRequestHandler : public HttpSysRequestHandler -{ - inline PHTTP_REQUEST HttpRequest() { return (PHTTP_REQUEST)m_RequestBuffer; } - inline uint32_t RequestBufferSize() const { return sizeof m_RequestBuffer; } - - InitialRequestHandler(HttpSysTransaction& InRequest) : HttpSysRequestHandler(InRequest) {} - ~InitialRequestHandler() {} - - virtual void IssueRequest() override; - virtual HttpSysRequestHandler* HandleCompletion(ULONG IoResult, ULONG_PTR NumberOfBytesTransferred) override; - - PHTTP_REQUEST m_HttpRequestPtr = (HTTP_REQUEST*)(m_RequestBuffer); - UCHAR m_RequestBuffer[16384 + sizeof(HTTP_REQUEST)]; -}; - -class HttpSysServerRequest : public HttpServerRequest -{ -public: - HttpSysServerRequest() = default; - HttpSysServerRequest(HttpSysTransaction& Tx, HttpService& Service); - ~HttpSysServerRequest() = default; - - virtual void ReadPayload(std::function<void(HttpServerRequest&, IoBuffer)>&& CompletionHandler) override; - virtual IoBuffer ReadPayload() override; - virtual void WriteResponse(HttpResponse HttpResponseCode) override; - virtual void WriteResponse(HttpResponse HttpResponseCode, HttpContentType ContentType, std::span<IoBuffer> Blobs) override; - virtual void WriteResponse(HttpResponse HttpResponseCode, HttpContentType ContentType, std::u8string_view ResponseString) override; - - bool m_IsInitialized = false; - HttpSysTransaction& m_HttpTx; - HttpMessageResponseRequest* m_Response = nullptr; // TODO: make this more general -}; - -/** HTTP transaction - - There will be an instance of this per pending and in-flight HTTP transaction - - */ -class HttpSysTransaction final -{ -public: - HttpSysTransaction(HttpSysServer& Server) : m_HttpServer(Server), m_HttpHandler(&m_InitialHttpHandler) {} - - virtual ~HttpSysTransaction() {} - - enum class Status - { - kDone, - kRequestPending - }; - - Status HandleCompletion(ULONG IoResult, ULONG_PTR NumberOfBytesTransferred); - - static void __stdcall IoCompletionCallback(PTP_CALLBACK_INSTANCE Instance, - PVOID pContext /* HttpSysServer */, - PVOID pOverlapped, - ULONG IoResult, - ULONG_PTR NumberOfBytesTransferred, - PTP_IO Io); - - void IssueInitialRequest(); - PTP_IO Iocp(); - HANDLE RequestQueueHandle(); - inline OVERLAPPED* Overlapped() { return &m_HttpOverlapped; } - inline HttpSysServer& Server() { return m_HttpServer; } - - inline PHTTP_REQUEST HttpRequest() { return m_InitialHttpHandler.HttpRequest(); } - -private: - OVERLAPPED m_HttpOverlapped{}; - HttpSysServer& m_HttpServer; - HttpSysRequestHandler* m_HttpHandler{nullptr}; // Tracks which handler is due to handle the next I/O completion event - RwLock m_CompletionMutex; - InitialRequestHandler m_InitialHttpHandler{*this}; -}; - -////////////////////////////////////////////////////////////////////////// - -class HttpPayloadReadRequest : public HttpSysRequestHandler -{ -public: - HttpPayloadReadRequest(HttpSysTransaction& InRequest) : HttpSysRequestHandler(InRequest) {} - - virtual void IssueRequest() override; - virtual HttpSysRequestHandler* HandleCompletion(ULONG IoResult, ULONG_PTR NumberOfBytesTransferred) override; -}; - -void -HttpPayloadReadRequest::IssueRequest() -{ -} - -HttpSysRequestHandler* -HttpPayloadReadRequest::HandleCompletion(ULONG IoResult, ULONG_PTR NumberOfBytesTransferred) -{ - ZEN_UNUSED(IoResult, NumberOfBytesTransferred); - return nullptr; -} - -////////////////////////////////////////////////////////////////////////// - -class HttpMessageResponseRequest : public HttpSysRequestHandler -{ -public: - HttpMessageResponseRequest(HttpSysTransaction& InRequest, uint16_t ResponseCode); - HttpMessageResponseRequest(HttpSysTransaction& InRequest, uint16_t ResponseCode, const char* Message); - HttpMessageResponseRequest(HttpSysTransaction& InRequest, uint16_t ResponseCode, const void* Payload, size_t PayloadSize); - HttpMessageResponseRequest(HttpSysTransaction& InRequest, uint16_t ResponseCode, std::span<IoBuffer> Blobs); - ~HttpMessageResponseRequest(); - - virtual void IssueRequest() override; - virtual HttpSysRequestHandler* HandleCompletion(ULONG IoResult, ULONG_PTR NumberOfBytesTransferred) override; - - void SuppressResponseBody(); - -private: - std::vector<HTTP_DATA_CHUNK> m_HttpDataChunks; - uint64_t m_TotalDataSize = 0; // Sum of all chunk sizes - - uint16_t m_HttpResponseCode = 0; - uint32_t m_NextDataChunkOffset = 0; // This is used for responses where the number of chunks exceed the maximum number for one API call - uint32_t m_RemainingChunkCount = 0; - bool m_IsInitialResponse = true; - - void Initialize(uint16_t ResponseCode, std::span<IoBuffer> Blobs); - - std::vector<IoBuffer> m_DataBuffers; -}; - -HttpMessageResponseRequest::HttpMessageResponseRequest(HttpSysTransaction& InRequest, uint16_t ResponseCode) -: HttpSysRequestHandler(InRequest) -{ - std::array<IoBuffer, 0> buffers; - - Initialize(ResponseCode, buffers); -} - -HttpMessageResponseRequest::HttpMessageResponseRequest(HttpSysTransaction& InRequest, uint16_t ResponseCode, const char* Message) -: HttpSysRequestHandler(InRequest) -{ - IoBuffer MessageBuffer(IoBuffer::Wrap, Message, strlen(Message)); - std::array<IoBuffer, 1> buffers({MessageBuffer}); - - Initialize(ResponseCode, buffers); -} - -HttpMessageResponseRequest::HttpMessageResponseRequest(HttpSysTransaction& InRequest, - uint16_t ResponseCode, - const void* Payload, - size_t PayloadSize) -: HttpSysRequestHandler(InRequest) -{ - IoBuffer MessageBuffer(IoBuffer::Wrap, Payload, PayloadSize); - std::array<IoBuffer, 1> buffers({MessageBuffer}); - - Initialize(ResponseCode, buffers); -} - -HttpMessageResponseRequest::HttpMessageResponseRequest(HttpSysTransaction& InRequest, uint16_t ResponseCode, std::span<IoBuffer> Blobs) -: HttpSysRequestHandler(InRequest) -{ - Initialize(ResponseCode, Blobs); -} - -HttpMessageResponseRequest::~HttpMessageResponseRequest() -{ -} - -void -HttpMessageResponseRequest::Initialize(uint16_t ResponseCode, std::span<IoBuffer> Blobs) -{ - m_HttpResponseCode = ResponseCode; - - const uint32_t ChunkCount = (uint32_t)Blobs.size(); - - m_HttpDataChunks.resize(ChunkCount); - m_DataBuffers.reserve(ChunkCount); - - for (IoBuffer& Buffer : Blobs) - { - m_DataBuffers.emplace_back(std::move(Buffer)).MakeOwned(); - } - - // Initialize the full array up front - - uint64_t LocalDataSize = 0; - - { - PHTTP_DATA_CHUNK ChunkPtr = m_HttpDataChunks.data(); - - for (IoBuffer& Buffer : m_DataBuffers) - { - const ULONG BufferDataSize = (ULONG)Buffer.Size(); - - ZEN_ASSERT(BufferDataSize); - - IoBufferFileReference FileRef; - if (Buffer.GetFileReference(/* out */ FileRef)) - { - ChunkPtr->DataChunkType = HttpDataChunkFromFileHandle; - ChunkPtr->FromFileHandle.FileHandle = FileRef.FileHandle; - ChunkPtr->FromFileHandle.ByteRange.StartingOffset.QuadPart = FileRef.FileChunkOffset; - ChunkPtr->FromFileHandle.ByteRange.Length.QuadPart = BufferDataSize; - } - else - { - ChunkPtr->DataChunkType = HttpDataChunkFromMemory; - ChunkPtr->FromMemory.pBuffer = (void*)Buffer.Data(); - ChunkPtr->FromMemory.BufferLength = BufferDataSize; - } - ++ChunkPtr; - - LocalDataSize += BufferDataSize; - } - } - - m_RemainingChunkCount = ChunkCount; - m_TotalDataSize = LocalDataSize; -} - -void -HttpMessageResponseRequest::SuppressResponseBody() -{ - m_RemainingChunkCount = 0; - m_HttpDataChunks.clear(); - m_DataBuffers.clear(); -} - -HttpSysRequestHandler* -HttpMessageResponseRequest::HandleCompletion(ULONG IoResult, ULONG_PTR NumberOfBytesTransferred) -{ - ZEN_UNUSED(NumberOfBytesTransferred); - ZEN_UNUSED(IoResult); - - if (m_RemainingChunkCount == 0) - { - return nullptr; // All done - } - - return this; -} - -void -HttpMessageResponseRequest::IssueRequest() -{ - HttpSysTransaction& Tx = Transaction(); - HTTP_REQUEST* const HttpReq = Tx.HttpRequest(); - PTP_IO const Iocp = Tx.Iocp(); - - StartThreadpoolIo(Iocp); - - // Split payload into batches to play well with the underlying API - - const int MaxChunksPerCall = 9999; - - const int ThisRequestChunkCount = std::min<int>(m_RemainingChunkCount, MaxChunksPerCall); - const int ThisRequestChunkOffset = m_NextDataChunkOffset; - - m_RemainingChunkCount -= ThisRequestChunkCount; - m_NextDataChunkOffset += ThisRequestChunkCount; - - ULONG SendFlags = 0; - - if (m_RemainingChunkCount) - { - // We need to make more calls to send the full amount of data - SendFlags |= HTTP_SEND_RESPONSE_FLAG_MORE_DATA; - } - - ULONG SendResult = 0; - - if (m_IsInitialResponse) - { - // Populate response structure - - HTTP_RESPONSE HttpResponse = {}; - - HttpResponse.EntityChunkCount = USHORT(ThisRequestChunkCount); - HttpResponse.pEntityChunks = m_HttpDataChunks.data() + ThisRequestChunkOffset; - - // Content-length header - - char ContentLengthString[32]; - _ui64toa_s(m_TotalDataSize, ContentLengthString, sizeof ContentLengthString, 10); - - PHTTP_KNOWN_HEADER ContentLengthHeader = &HttpResponse.Headers.KnownHeaders[HttpHeaderContentLength]; - ContentLengthHeader->pRawValue = ContentLengthString; - ContentLengthHeader->RawValueLength = (USHORT)strlen(ContentLengthString); - - // Content-type header - - PHTTP_KNOWN_HEADER ContentTypeHeader = &HttpResponse.Headers.KnownHeaders[HttpHeaderContentType]; - - ContentTypeHeader->pRawValue = "application/octet-stream"; /* TODO! We must respect the content type specified */ - ContentTypeHeader->RawValueLength = (USHORT)strlen(ContentTypeHeader->pRawValue); - - HttpResponse.StatusCode = m_HttpResponseCode; - HttpResponse.pReason = ReasonStringForHttpResultCode(m_HttpResponseCode); - HttpResponse.ReasonLength = (USHORT)strlen(HttpResponse.pReason); - - // Cache policy - - HTTP_CACHE_POLICY CachePolicy; - - CachePolicy.Policy = HttpCachePolicyNocache; // HttpCachePolicyUserInvalidates; - CachePolicy.SecondsToLive = 0; - - // Initial response API call - - SendResult = HttpSendHttpResponse(Tx.RequestQueueHandle(), - HttpReq->RequestId, - SendFlags, - &HttpResponse, - &CachePolicy, - NULL, - NULL, - 0, - Tx.Overlapped(), - NULL); - - m_IsInitialResponse = false; - } - else - { - // Subsequent response API calls - - SendResult = HttpSendResponseEntityBody(Tx.RequestQueueHandle(), - HttpReq->RequestId, - SendFlags, - (USHORT)ThisRequestChunkCount, // EntityChunkCount - &m_HttpDataChunks[ThisRequestChunkOffset], // EntityChunks - NULL, // BytesSent - NULL, // Reserved1 - 0, // Reserved2 - Tx.Overlapped(), // Overlapped - NULL // LogData - ); - } - - if ((SendResult != NO_ERROR) // Synchronous completion, but the completion event will still be posted to IOCP - && (SendResult != ERROR_IO_PENDING) // Asynchronous completion - ) - { - // Some error occurred, no completion will be posted - - CancelThreadpoolIo(Iocp); - - spdlog::error("failed to send HTTP response (error: {}) URL: {}", SendResult, HttpReq->pRawUrl); - - throw HttpServerException("Failed to send HTTP response", SendResult); - } -} - -////////////////////////////////////////////////////////////////////////// - -HttpSysServer::HttpSysServer(int ThreadCount) : m_ThreadPool(ThreadCount) -{ - ULONG Result = HttpInitialize(HTTPAPI_VERSION_2, HTTP_INITIALIZE_SERVER, nullptr); - - if (Result != NO_ERROR) - { - return; - } - - m_IsHttpInitialized = true; - m_IsOk = true; -} - -HttpSysServer::~HttpSysServer() -{ - if (m_IsHttpInitialized) - { - HttpTerminate(HTTP_INITIALIZE_SERVER, nullptr); - } -} - -void -HttpSysServer::Initialize(const wchar_t* UrlPath) -{ - // check(bIsOk); - - ULONG Result = HttpCreateServerSession(HTTPAPI_VERSION_2, &m_HttpSessionId, 0); - - if (Result != NO_ERROR) - { - // Flag error - - return; - } - - Result = HttpCreateUrlGroup(m_HttpSessionId, &m_HttpUrlGroupId, 0); - - if (Result != NO_ERROR) - { - // Flag error - - return; - } - - m_BaseUri = UrlPath; - - Result = HttpAddUrlToUrlGroup(m_HttpUrlGroupId, UrlPath, /* #TODO UrlContext */ HTTP_URL_CONTEXT(0), 0); - - if (Result != NO_ERROR) - { - // Flag error - - return; - } - - HTTP_BINDING_INFO HttpBindingInfo = {{0}, 0}; - - Result = HttpCreateRequestQueue(HTTPAPI_VERSION_2, NULL, NULL, 0, &m_RequestQueueHandle); - - if (Result != NO_ERROR) - { - // Flag error! - - return; - } - - HttpBindingInfo.Flags.Present = 1; - HttpBindingInfo.RequestQueueHandle = m_RequestQueueHandle; - - Result = HttpSetUrlGroupProperty(m_HttpUrlGroupId, HttpServerBindingProperty, &HttpBindingInfo, sizeof(HttpBindingInfo)); - - if (Result != NO_ERROR) - { - // Flag error! - - return; - } - - // Create I/O completion port - - m_ThreadPool.CreateIocp(m_RequestQueueHandle, HttpSysTransaction::IoCompletionCallback, this); - - // Check result! -} - -void -HttpSysServer::StartServer() -{ - int RequestCount = 32; - - for (int i = 0; i < RequestCount; ++i) - { - IssueNewRequestMaybe(); - } -} - -void -HttpSysServer::Run(bool TestMode) -{ - if (TestMode == false) - { - zen::logging::ConsoleLog().info("Zen Server running. Press ESC or Q to quit"); - } - - do - { - int WaitTimeout = -1; - - if (!TestMode) - { - WaitTimeout = 1000; - } - - if (!TestMode && _kbhit() != 0) - { - char c = (char)_getch(); - - if (c == 27 || c == 'Q' || c == 'q') - { - RequestApplicationExit(0); - } - } - - m_ShutdownEvent.Wait(WaitTimeout); - } while (!IsApplicationExitRequested()); -} - -void -HttpSysServer::OnHandlingRequest() -{ - --m_PendingRequests; - - if (m_PendingRequests > m_MinPendingRequests) - { - // We have more than the minimum number of requests pending, just let someone else - // enqueue new requests - return; - } - - IssueNewRequestMaybe(); -} - -void -HttpSysServer::IssueNewRequestMaybe() -{ - if (m_PendingRequests.load(std::memory_order::relaxed) >= m_MaxPendingRequests) - { - return; - } - - std::unique_ptr<HttpSysTransaction> Request = std::make_unique<HttpSysTransaction>(*this); - - Request->IssueInitialRequest(); - - // This may end up exceeding the MaxPendingRequests limit, but it's not - // really a problem. I'm doing it this way mostly to avoid dealing with - // exceptions here - ++m_PendingRequests; - - Request.release(); -} - -void -HttpSysServer::RegisterService(const char* UrlPath, HttpService& Service) -{ - if (UrlPath[0] == '/') - { - ++UrlPath; - } - - const std::wstring Path16 = UTF8_to_wstring(UrlPath); - Service.SetUriPrefixLength(Path16.size() + 1 /* leading slash */); - - // Convert to wide string - - std::wstring Url16 = m_BaseUri + Path16; - - ULONG Result = HttpAddUrlToUrlGroup(m_HttpUrlGroupId, Url16.c_str(), HTTP_URL_CONTEXT(&Service), 0 /* Reserved */); - - if (Result != NO_ERROR) - { - spdlog::error("HttpAddUrlToUrlGroup failed with result {}", Result); - - return; - } -} - -void -HttpSysServer::RemoveEndpoint(const char* UrlPath, HttpService& Service) -{ - ZEN_UNUSED(Service); - - if (UrlPath[0] == '/') - { - ++UrlPath; - } - - const std::wstring Path16 = UTF8_to_wstring(UrlPath); - - // Convert to wide string - - std::wstring Url16 = m_BaseUri + Path16; - - ULONG Result = HttpRemoveUrlFromUrlGroup(m_HttpUrlGroupId, Url16.c_str(), 0); - - if (Result != NO_ERROR) - { - spdlog::error("HttpRemoveUrlFromUrlGroup failed with result {}", Result); - } -} - -////////////////////////////////////////////////////////////////////////// - -HttpSysServerRequest::HttpSysServerRequest(HttpSysTransaction& Tx, HttpService& Service) : m_IsInitialized(true), m_HttpTx(Tx) -{ - PHTTP_REQUEST HttpRequestPtr = Tx.HttpRequest(); - - const int PrefixLength = Service.UriPrefixLength(); - const int AbsPathLength = HttpRequestPtr->CookedUrl.AbsPathLength / sizeof(char16_t); - - if (AbsPathLength >= PrefixLength) - { - // We convert the URI immediately because most of the code involved prefers to deal - // with utf8. This has some performance impact which I'd prefer to avoid but for now - // we just have to live with it - - WideToUtf8({(char16_t*)HttpRequestPtr->CookedUrl.pAbsPath + PrefixLength, gsl::narrow<size_t>(AbsPathLength - PrefixLength)}, - m_Uri); - } - else - { - m_Uri.Reset(); - } - - if (auto QueryStringLength = HttpRequestPtr->CookedUrl.QueryStringLength) - { - --QueryStringLength; - - WideToUtf8({(char16_t*)(HttpRequestPtr->CookedUrl.pQueryString) + 1, QueryStringLength / sizeof(char16_t)}, m_QueryString); - } - else - { - m_QueryString.Reset(); - } - - switch (HttpRequestPtr->Verb) - { - case HttpVerbOPTIONS: - m_Verb = HttpVerb::kOptions; - break; - - case HttpVerbGET: - m_Verb = HttpVerb::kGet; - break; - - case HttpVerbHEAD: - m_Verb = HttpVerb::kHead; - break; - - case HttpVerbPOST: - m_Verb = HttpVerb::kPost; - break; - - case HttpVerbPUT: - m_Verb = HttpVerb::kPut; - break; - - case HttpVerbDELETE: - m_Verb = HttpVerb::kDelete; - break; - - case HttpVerbCOPY: - m_Verb = HttpVerb::kCopy; - break; - - default: - // TODO: invalid request? - m_Verb = (HttpVerb)0; - break; - } - - const HTTP_KNOWN_HEADER& clh = HttpRequestPtr->Headers.KnownHeaders[HttpHeaderContentLength]; - std::string_view cl(clh.pRawValue, clh.RawValueLength); - std::from_chars(cl.data(), cl.data() + cl.size(), m_ContentLength); - - const HTTP_KNOWN_HEADER& CtHdr = HttpRequestPtr->Headers.KnownHeaders[HttpHeaderContentType]; - m_ContentType = MapContentType({CtHdr.pRawValue, CtHdr.RawValueLength}); -} - -void -HttpSysServerRequest::ReadPayload(std::function<void(HttpServerRequest&, IoBuffer)>&& CompletionHandler) -{ - ZEN_UNUSED(CompletionHandler); -} - -IoBuffer -HttpSysServerRequest::ReadPayload() -{ - // This is presently synchronous for simplicity, but we - // need to implement an asynchronous version also - - HTTP_REQUEST* const HttpReq = m_HttpTx.HttpRequest(); - - IoBuffer PayloadBuffer(m_ContentLength); - - HttpContentType ContentType = RequestContentType(); - PayloadBuffer.SetContentType(ContentType); - - uint64_t BytesToRead = m_ContentLength; - - uint8_t* ReadPointer = reinterpret_cast<uint8_t*>(PayloadBuffer.MutableData()); - - // First deal with any payload which has already been copied - // into our request buffer - - const int EntityChunkCount = HttpReq->EntityChunkCount; - - for (int i = 0; i < EntityChunkCount; ++i) - { - HTTP_DATA_CHUNK& EntityChunk = HttpReq->pEntityChunks[i]; - - ZEN_ASSERT(EntityChunk.DataChunkType == HttpDataChunkFromMemory); - - const uint64_t BufferLength = EntityChunk.FromMemory.BufferLength; - - ZEN_ASSERT(BufferLength <= BytesToRead); - - memcpy(ReadPointer, EntityChunk.FromMemory.pBuffer, BufferLength); - - ReadPointer += BufferLength; - BytesToRead -= BufferLength; - } - - if (BytesToRead == 0) - { - PayloadBuffer.MakeImmutable(); - - return PayloadBuffer; - } - - // Call http.sys API to receive the remaining data SYNCHRONOUSLY - - static const uint64_t kMaxBytesPerApiCall = 1 * 1024 * 1024; - - while (BytesToRead) - { - ULONG BytesRead = 0; - - const uint64_t BytesToReadThisCall = zen::Min(BytesToRead, kMaxBytesPerApiCall); - - ULONG ApiResult = HttpReceiveRequestEntityBody(m_HttpTx.RequestQueueHandle(), - HttpReq->RequestId, - 0, /* Flags */ - ReadPointer, - gsl::narrow<ULONG>(BytesToReadThisCall), - &BytesRead, - NULL /* Overlapped */ - ); - - if (ApiResult != NO_ERROR && ApiResult != ERROR_HANDLE_EOF) - { - throw HttpServerException("payload read failed", ApiResult); - } - - BytesToRead -= BytesRead; - ReadPointer += BytesRead; - } - - PayloadBuffer.MakeImmutable(); - - return PayloadBuffer; -} - -void -HttpSysServerRequest::WriteResponse(HttpResponse HttpResponseCode) -{ - ZEN_ASSERT(m_IsHandled == false); - - m_Response = new HttpMessageResponseRequest(m_HttpTx, (uint16_t)HttpResponseCode); - - if (m_SuppressBody) - { - m_Response->SuppressResponseBody(); - } - - m_IsHandled = true; -} - -void -HttpSysServerRequest::WriteResponse(HttpResponse HttpResponseCode, HttpContentType ContentType, std::span<IoBuffer> Blobs) -{ - ZEN_ASSERT(m_IsHandled == false); - ZEN_UNUSED(ContentType); - - m_Response = new HttpMessageResponseRequest(m_HttpTx, (uint16_t)HttpResponseCode, Blobs); - - if (m_SuppressBody) - { - m_Response->SuppressResponseBody(); - } - - m_IsHandled = true; -} - -void -HttpSysServerRequest::WriteResponse(HttpResponse HttpResponseCode, HttpContentType ContentType, std::u8string_view ResponseString) -{ - ZEN_ASSERT(m_IsHandled == false); - ZEN_UNUSED(ContentType); - - m_Response = new HttpMessageResponseRequest(m_HttpTx, (uint16_t)HttpResponseCode, ResponseString.data(), ResponseString.size()); - - if (m_SuppressBody) - { - m_Response->SuppressResponseBody(); - } - - m_IsHandled = true; -} - -////////////////////////////////////////////////////////////////////////// - -PTP_IO -HttpSysTransaction::Iocp() -{ - return m_HttpServer.m_ThreadPool.Iocp(); -} - -HANDLE -HttpSysTransaction::RequestQueueHandle() -{ - return m_HttpServer.m_RequestQueueHandle; -} - -void -HttpSysTransaction::IssueInitialRequest() -{ - m_InitialHttpHandler.IssueRequest(); -} - -void -HttpSysTransaction::IoCompletionCallback(PTP_CALLBACK_INSTANCE Instance, - PVOID pContext /* HttpSysServer */, - PVOID pOverlapped, - ULONG IoResult, - ULONG_PTR NumberOfBytesTransferred, - PTP_IO Io) -{ - UNREFERENCED_PARAMETER(Io); - UNREFERENCED_PARAMETER(Instance); - UNREFERENCED_PARAMETER(pContext); - - // Note that for a given transaction we may be in this completion function on more - // than one thread at any given moment. This means we need to be careful about what - // happens in here - - HttpSysTransaction* Transaction = CONTAINING_RECORD(pOverlapped, HttpSysTransaction, m_HttpOverlapped); - - if (Transaction->HandleCompletion(IoResult, NumberOfBytesTransferred) == HttpSysTransaction::Status::kDone) - { - delete Transaction; - } -} - -HttpSysTransaction::Status -HttpSysTransaction::HandleCompletion(ULONG IoResult, ULONG_PTR NumberOfBytesTransferred) -{ - // We use this to ensure sequential execution of completion handlers - // for any given transaction. - RwLock::ExclusiveLockScope _(m_CompletionMutex); - - bool RequestPending = false; - - if (HttpSysRequestHandler* CurrentHandler = m_HttpHandler) - { - const bool IsInitialRequest = (CurrentHandler == &m_InitialHttpHandler); - - if (IsInitialRequest) - { - // Ensure we have a sufficient number of pending requests outstanding - m_HttpServer.OnHandlingRequest(); - } - - m_HttpHandler = CurrentHandler->HandleCompletion(IoResult, NumberOfBytesTransferred); - - if (m_HttpHandler) - { - try - { - m_HttpHandler->IssueRequest(); - - RequestPending = true; - } - catch (std::exception& Ex) - { - spdlog::error("exception caught from IssueRequest(): {}", Ex.what()); - - // something went wrong, no request is pending - } - } - else - { - if (IsInitialRequest == false) - { - delete CurrentHandler; - } - } - } - - // Ensure new requests are enqueued - m_HttpServer.IssueNewRequestMaybe(); - - if (RequestPending) - { - return Status::kRequestPending; - } - - return Status::kDone; -} - -////////////////////////////////////////////////////////////////////////// - -void -InitialRequestHandler::IssueRequest() -{ - PTP_IO Iocp = Transaction().Iocp(); - - StartThreadpoolIo(Iocp); - - HttpSysTransaction& Tx = Transaction(); - - HTTP_REQUEST* HttpReq = Tx.HttpRequest(); - - ULONG Result = HttpReceiveHttpRequest(Tx.RequestQueueHandle(), - HTTP_NULL_ID, - HTTP_RECEIVE_REQUEST_FLAG_COPY_BODY, - HttpReq, - RequestBufferSize(), - NULL, - Tx.Overlapped()); - - if (Result != ERROR_IO_PENDING && Result != NO_ERROR) - { - CancelThreadpoolIo(Iocp); - - if (Result == ERROR_MORE_DATA) - { - // ProcessReceiveAndPostResponse(pIoRequest, pServerContext->Io, ERROR_MORE_DATA); - } - - // CleanupHttpIoRequest(pIoRequest); - - spdlog::error("HttpReceiveHttpRequest failed, error {:x}", Result); - - return; - } -} - -HttpSysRequestHandler* -InitialRequestHandler::HandleCompletion(ULONG IoResult, ULONG_PTR NumberOfBytesTransferred) -{ - ZEN_UNUSED(IoResult); - ZEN_UNUSED(NumberOfBytesTransferred); - - // Route requests - - try - { - if (HttpService* Service = reinterpret_cast<HttpService*>(m_HttpRequestPtr->UrlContext)) - { - HttpSysServerRequest ThisRequest(Transaction(), *Service); - - Service->HandleRequest(ThisRequest); - - if (!ThisRequest.IsHandled()) - { - return new HttpMessageResponseRequest(Transaction(), 404, "Not found"); - } - - if (ThisRequest.m_Response) - { - return ThisRequest.m_Response; - } - } - - // Unable to route - return new HttpMessageResponseRequest(Transaction(), 404, "Item unknown"); - } - catch (std::exception& ex) - { - // TODO provide more meaningful error output - - return new HttpMessageResponseRequest(Transaction(), 500, ex.what()); - } -} - -////////////////////////////////////////////////////////////////////////// -// -// HttpServer interface implementation -// - -void -HttpSysServer::Initialize(int BasePort) -{ - using namespace std::literals; - - WideStringBuilder<64> BaseUri; - BaseUri << u8"http://*:"sv << int64_t(BasePort) << u8"/"sv; - - Initialize(BaseUri.c_str()); - StartServer(); -} - -void -HttpSysServer::RequestExit() -{ - m_ShutdownEvent.Set(); -} -void -HttpSysServer::RegisterService(HttpService& Service) -{ - RegisterService(Service.BaseUri(), Service); -} - -#endif // ZEN_PLATFORM_WINDOWS - -} // namespace zen diff --git a/zencore/httpsys.h b/zencore/httpsys.h deleted file mode 100644 index fbe293a47..000000000 --- a/zencore/httpsys.h +++ /dev/null @@ -1,61 +0,0 @@ -#pragma once - -#include <zencore/httpserver.h> - -#define _WINSOCKAPI_ -#include <zencore/windows.h> -#include "iothreadpool.h" - -#include <atlbase.h> -#include <http.h> - -namespace zen { - -/** - * @brief Windows implementation of HTTP server based on http.sys - * - * This requires elevation to function - */ -class HttpSysServer : public HttpServer -{ - friend class HttpSysTransaction; - -public: - explicit HttpSysServer(int ThreadCount); - ~HttpSysServer(); - - // HttpServer interface implementation - - virtual void Initialize(int BasePort) override; - virtual void Run(bool TestMode) override; - virtual void RequestExit() override; - virtual void RegisterService(HttpService& Service) override; - -private: - void Initialize(const wchar_t* UrlPath); - - void StartServer(); - void OnHandlingRequest(); - void IssueNewRequestMaybe(); - - inline bool IsOk() const { return m_IsOk; } - - void RegisterService(const char* Endpoint, HttpService& Service); - void RemoveEndpoint(const char* Endpoint, HttpService& Service); - -private: - bool m_IsOk = false; - bool m_IsHttpInitialized = false; - WinIoThreadPool m_ThreadPool; - - std::wstring m_BaseUri; // http://*:nnnn/ - HTTP_SERVER_SESSION_ID m_HttpSessionId = 0; - HTTP_URL_GROUP_ID m_HttpUrlGroupId = 0; - HANDLE m_RequestQueueHandle = 0; - std::atomic_int32_t m_PendingRequests{0}; - int32_t m_MinPendingRequests = 16; - int32_t m_MaxPendingRequests = 128; - Event m_ShutdownEvent; -}; - -} // namespace zen diff --git a/zencore/include/zencore/httpclient.h b/zencore/include/zencore/httpclient.h deleted file mode 100644 index 4b30eb09b..000000000 --- a/zencore/include/zencore/httpclient.h +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright Epic Games, Inc. All Rights Reserved. - -#pragma once - -#include "zencore.h" - -#include <zencore/string.h> -#include <gsl/gsl-lite.hpp> - -namespace zen { - -/** Asynchronous HTTP client implementation for Zen use cases - */ -class HttpClient -{ -public: -private: -}; - -} // namespace zen - -void httpclient_forcelink(); // internal diff --git a/zencore/include/zencore/httpserver.h b/zencore/include/zencore/httpserver.h deleted file mode 100644 index 593ff7344..000000000 --- a/zencore/include/zencore/httpserver.h +++ /dev/null @@ -1,446 +0,0 @@ -// Copyright Epic Games, Inc. All Rights Reserved. - -#pragma once - -#include "zencore.h" - -#include <zencore/enumflags.h> -#include <zencore/iobuffer.h> -#include <zencore/refcount.h> -#include <zencore/string.h> - -#include <functional> -#include <gsl/gsl-lite.hpp> -#include <list> -#include <regex> -#include <span> -#include <unordered_map> - -namespace zen { - -using HttpContentType = ZenContentType; - -class IoBuffer; -class CbObject; -class CbPackage; -class StringBuilderBase; - -enum class HttpVerb -{ - kGet = 1 << 0, - kPut = 1 << 1, - kPost = 1 << 2, - kDelete = 1 << 3, - kHead = 1 << 4, - kCopy = 1 << 5, - kOptions = 1 << 6 -}; - -gsl_DEFINE_ENUM_BITMASK_OPERATORS(HttpVerb); - -enum class HttpResponse -{ - // 1xx - Informational - - Continue = 100, //!< Indicates that the initial part of a request has been received and has not yet been rejected by the server. - SwitchingProtocols = 101, //!< Indicates that the server understands and is willing to comply with the client's request, via the - //!< Upgrade header field, for a change in the application protocol being used on this connection. - Processing = 102, //!< Is an interim response used to inform the client that the server has accepted the complete request, but has not - //!< yet completed it. - EarlyHints = 103, //!< Indicates to the client that the server is likely to send a final response with the header fields included in - //!< the informational response. - - // 2xx - Successful - - OK = 200, //!< Indicates that the request has succeeded. - Created = 201, //!< Indicates that the request has been fulfilled and has resulted in one or more new resources being created. - Accepted = 202, //!< Indicates that the request has been accepted for processing, but the processing has not been completed. - NonAuthoritativeInformation = 203, //!< Indicates that the request was successful but the enclosed payload has been modified from that - //!< of the origin server's 200 (OK) response by a transforming proxy. - NoContent = 204, //!< Indicates that the server has successfully fulfilled the request and that there is no additional content to send - //!< in the response payload body. - ResetContent = 205, //!< Indicates that the server has fulfilled the request and desires that the user agent reset the \"document - //!< view\", which caused the request to be sent, to its original state as received from the origin server. - PartialContent = 206, //!< Indicates that the server is successfully fulfilling a range request for the target resource by transferring - //!< one or more parts of the selected representation that correspond to the satisfiable ranges found in the - //!< requests's Range header field. - MultiStatus = 207, //!< Provides status for multiple independent operations. - AlreadyReported = 208, //!< Used inside a DAV:propstat response element to avoid enumerating the internal members of multiple bindings - //!< to the same collection repeatedly. [RFC 5842] - IMUsed = 226, //!< The server has fulfilled a GET request for the resource, and the response is a representation of the result of one - //!< or more instance-manipulations applied to the current instance. - - // 3xx - Redirection - - MultipleChoices = 300, //!< Indicates that the target resource has more than one representation, each with its own more specific - //!< identifier, and information about the alternatives is being provided so that the user (or user agent) can - //!< select a preferred representation by redirecting its request to one or more of those identifiers. - MovedPermanently = 301, //!< Indicates that the target resource has been assigned a new permanent URI and any future references to this - //!< resource ought to use one of the enclosed URIs. - Found = 302, //!< Indicates that the target resource resides temporarily under a different URI. - SeeOther = 303, //!< Indicates that the server is redirecting the user agent to a different resource, as indicated by a URI in the - //!< Location header field, that is intended to provide an indirect response to the original request. - NotModified = 304, //!< Indicates that a conditional GET request has been received and would have resulted in a 200 (OK) response if it - //!< were not for the fact that the condition has evaluated to false. - UseProxy = 305, //!< \deprecated \parblock Due to security concerns regarding in-band configuration of a proxy. \endparblock - //!< The requested resource MUST be accessed through the proxy given by the Location field. - TemporaryRedirect = 307, //!< Indicates that the target resource resides temporarily under a different URI and the user agent MUST NOT - //!< change the request method if it performs an automatic redirection to that URI. - PermanentRedirect = 308, //!< The target resource has been assigned a new permanent URI and any future references to this resource - //!< ought to use one of the enclosed URIs. [...] This status code is similar to 301 Moved Permanently - //!< (Section 7.3.2 of rfc7231), except that it does not allow rewriting the request method from POST to GET. - - // 4xx - Client Error - BadRequest = 400, //!< Indicates that the server cannot or will not process the request because the received syntax is invalid, - //!< nonsensical, or exceeds some limitation on what the server is willing to process. - Unauthorized = 401, //!< Indicates that the request has not been applied because it lacks valid authentication credentials for the - //!< target resource. - PaymentRequired = 402, //!< *Reserved* - Forbidden = 403, //!< Indicates that the server understood the request but refuses to authorize it. - NotFound = 404, //!< Indicates that the origin server did not find a current representation for the target resource or is not willing - //!< to disclose that one exists. - MethodNotAllowed = 405, //!< Indicates that the method specified in the request-line is known by the origin server but not supported by - //!< the target resource. - NotAcceptable = 406, //!< Indicates that the target resource does not have a current representation that would be acceptable to the - //!< user agent, according to the proactive negotiation header fields received in the request, and the server is - //!< unwilling to supply a default representation. - ProxyAuthenticationRequired = - 407, //!< Is similar to 401 (Unauthorized), but indicates that the client needs to authenticate itself in order to use a proxy. - RequestTimeout = - 408, //!< Indicates that the server did not receive a complete request message within the time that it was prepared to wait. - Conflict = 409, //!< Indicates that the request could not be completed due to a conflict with the current state of the resource. - Gone = 410, //!< Indicates that access to the target resource is no longer available at the origin server and that this condition is - //!< likely to be permanent. - LengthRequired = 411, //!< Indicates that the server refuses to accept the request without a defined Content-Length. - PreconditionFailed = - 412, //!< Indicates that one or more preconditions given in the request header fields evaluated to false when tested on the server. - PayloadTooLarge = 413, //!< Indicates that the server is refusing to process a request because the request payload is larger than the - //!< server is willing or able to process. - URITooLong = 414, //!< Indicates that the server is refusing to service the request because the request-target is longer than the - //!< server is willing to interpret. - UnsupportedMediaType = 415, //!< Indicates that the origin server is refusing to service the request because the payload is in a format - //!< not supported by the target resource for this method. - RangeNotSatisfiable = 416, //!< Indicates that none of the ranges in the request's Range header field overlap the current extent of the - //!< selected resource or that the set of ranges requested has been rejected due to invalid ranges or an - //!< excessive request of small or overlapping ranges. - ExpectationFailed = 417, //!< Indicates that the expectation given in the request's Expect header field could not be met by at least - //!< one of the inbound servers. - ImATeapot = 418, //!< Any attempt to brew coffee with a teapot should result in the error code 418 I'm a teapot. - UnprocessableEntity = 422, //!< Means the server understands the content type of the request entity (hence a 415(Unsupported Media - //!< Type) status code is inappropriate), and the syntax of the request entity is correct (thus a 400 (Bad - //!< Request) status code is inappropriate) but was unable to process the contained instructions. - Locked = 423, //!< Means the source or destination resource of a method is locked. - FailedDependency = 424, //!< Means that the method could not be performed on the resource because the requested action depended on - //!< another action and that action failed. - UpgradeRequired = 426, //!< Indicates that the server refuses to perform the request using the current protocol but might be willing to - //!< do so after the client upgrades to a different protocol. - PreconditionRequired = 428, //!< Indicates that the origin server requires the request to be conditional. - TooManyRequests = 429, //!< Indicates that the user has sent too many requests in a given amount of time (\"rate limiting\"). - RequestHeaderFieldsTooLarge = - 431, //!< Indicates that the server is unwilling to process the request because its header fields are too large. - UnavailableForLegalReasons = - 451, //!< This status code indicates that the server is denying access to the resource in response to a legal demand. - - // 5xx - Server Error - - InternalServerError = - 500, //!< Indicates that the server encountered an unexpected condition that prevented it from fulfilling the request. - NotImplemented = 501, //!< Indicates that the server does not support the functionality required to fulfill the request. - BadGateway = 502, //!< Indicates that the server, while acting as a gateway or proxy, received an invalid response from an inbound - //!< server it accessed while attempting to fulfill the request. - ServiceUnavailable = 503, //!< Indicates that the server is currently unable to handle the request due to a temporary overload or - //!< scheduled maintenance, which will likely be alleviated after some delay. - GatewayTimeout = 504, //!< Indicates that the server, while acting as a gateway or proxy, did not receive a timely response from an - //!< upstream server it needed to access in order to complete the request. - HTTPVersionNotSupported = 505, //!< Indicates that the server does not support, or refuses to support, the protocol version that was - //!< used in the request message. - VariantAlsoNegotiates = - 506, //!< Indicates that the server has an internal configuration error: the chosen variant resource is configured to engage in - //!< transparent content negotiation itself, and is therefore not a proper end point in the negotiation process. - InsufficientStorage = 507, //!< Means the method could not be performed on the resource because the server is unable to store the - //!< representation needed to successfully complete the request. - LoopDetected = 508, //!< Indicates that the server terminated an operation because it encountered an infinite loop while processing a - //!< request with "Depth: infinity". [RFC 5842] - NotExtended = 510, //!< The policy for accessing the resource has not been met in the request. [RFC 2774] - NetworkAuthenticationRequired = 511, //!< Indicates that the client needs to authenticate to gain network access. -}; - -/** HTTP Server Request - */ -class HttpServerRequest -{ -public: - HttpServerRequest(); - ~HttpServerRequest(); - - // Synchronous operations - - [[nodiscard]] inline std::string_view RelativeUri() const { return m_Uri; } // Returns URI without service prefix - [[nodiscard]] inline std::string_view QueryString() const { return m_QueryString; } - inline bool IsHandled() const { return m_IsHandled; } - - struct QueryParams - { - std::vector<std::pair<std::string_view, std::string_view>> KvPairs; - - std::string_view GetValue(std::string_view ParamName) - { - for (const auto& Kv : KvPairs) - { - const std::string_view& Key = Kv.first; - - if (Key.size() == ParamName.size()) - { - if (0 == _strnicmp(Key.data(), ParamName.data(), Key.size())) - { - return Kv.second; - } - } - } - - return std::string_view(); - } - }; - - QueryParams GetQueryParams(); - - inline HttpVerb RequestVerb() const { return m_Verb; } - inline HttpContentType RequestContentType() { return m_ContentType; } - - const char* HeaderAccept() const; - const char* HeaderAcceptEncoding() const; - const char* HeaderContentType() const; - const char* HeaderContentEncoding() const; - inline uint64_t HeaderContentLength() const { return m_ContentLength; } - - void SetSuppressResponseBody() { m_SuppressBody = true; } - - // Asynchronous operations - - /** Read POST/PUT payload - - This will return a null buffer if the contents are not fully available yet, and the handler should - at that point return - another completion request will be issued once the contents have been received - fully. - - NOTE: in practice, via the http.sys implementation this always operates synchronously. This should - be updated to provide fully asynchronous operation for better scalability on shared instances - */ - virtual IoBuffer ReadPayload() = 0; - - virtual void ReadPayload(std::function<void(HttpServerRequest&, IoBuffer)>&& CompletionHandler) = 0; - - ZENCORE_API CbObject ReadPayloadObject(); - ZENCORE_API CbPackage ReadPayloadPackage(); - - /** Respond with payload - - Note that this is destructive in the sense that the IoBuffer instances referred to by Blobs will be - moved into our response handler array where they are kept alive, in order to reduce ref-counting storms - */ - virtual void WriteResponse(HttpResponse HttpResponseCode, HttpContentType ContentType, std::span<IoBuffer> Blobs) = 0; - virtual void WriteResponse(HttpResponse HttpResponseCode, HttpContentType ContentType, IoBuffer Blob); - virtual void WriteResponse(HttpResponse HttpResponseCode) = 0; - - virtual void WriteResponse(HttpResponse HttpResponseCode, HttpContentType ContentType, std::u8string_view ResponseString) = 0; - - void WriteResponse(HttpResponse HttpResponseCode, CbObject Data); - void WriteResponse(HttpResponse HttpResponseCode, CbPackage Package); - void WriteResponse(HttpResponse HttpResponseCode, HttpContentType ContentType, std::string_view ResponseString); - -protected: - bool m_IsHandled = false; - bool m_SuppressBody = false; - HttpVerb m_Verb = HttpVerb::kGet; - uint64_t m_ContentLength = ~0ull; - HttpContentType m_ContentType = HttpContentType::kBinary; - ExtendableStringBuilder<256> m_Uri; - ExtendableStringBuilder<256> m_QueryString; -}; - -class HttpServerException : public std::exception -{ -public: - HttpServerException(const char* Message, uint32_t Error); - - virtual const char* what() const override; - -private: - uint32_t m_ErrorCode; - std::string m_Message; -}; - -/** - * Base class for implementing an HTTP "service" - * - * A service exposes one or more endpoints with a certain URI prefix - * - */ - -class HttpService -{ -public: - HttpService() = default; - virtual ~HttpService() = default; - - virtual const char* BaseUri() const = 0; - virtual void HandleRequest(HttpServerRequest& HttpServiceRequest) = 0; - - // Internals - - inline void SetUriPrefixLength(size_t PrefixLength) { m_UriPrefixLength = (int)PrefixLength; } - inline int UriPrefixLength() const { return m_UriPrefixLength; } - -private: - int m_UriPrefixLength = 0; -}; - -/** HTTP server - * - * Implements the main event loop to service HTTP requests, and handles routing - * requests to the appropriate endpoint handler as registered via AddEndpoint - */ -class HttpServer : public RefCounted -{ -public: - virtual void RegisterService(HttpService& Service) = 0; - virtual void Initialize(int BasePort) = 0; - virtual void Run(bool TestMode) = 0; - virtual void RequestExit() = 0; -}; - -Ref<HttpServer> CreateHttpServer(); - -////////////////////////////////////////////////////////////////////////// - -class HttpRouterRequest -{ -public: - HttpRouterRequest(HttpServerRequest& Request) : m_HttpRequest(Request) {} - - ZENCORE_API std::string GetCapture(uint32_t Index) const; - inline HttpServerRequest& ServerRequest() { return m_HttpRequest; } - -private: - using MatchResults_t = std::match_results<std::string_view::const_iterator>; - - HttpServerRequest& m_HttpRequest; - MatchResults_t m_Match; - - friend class HttpRequestRouter; -}; - -inline std::string -HttpRouterRequest::GetCapture(uint32_t Index) const -{ - ZEN_ASSERT(Index < m_Match.size()); - - return m_Match[Index]; -} - -////////////////////////////////////////////////////////////////////////// - -class PackageRequestContext -{ -public: - PackageRequestContext(); - ~PackageRequestContext(); - -private: -}; - -class PackageEndpointHandler -{ -public: - virtual void HandleRequest(HttpRouterRequest& Request) = 0; - -private: -}; - -/** HTTP request router helper - * - * This helper class allows a service implementer to register one or more - * endpoints using pattern matching (currently using regex matching) - * - * This is intended to be initialized once only, there is no thread - * safety so you can absolutely not add or remove endpoints once the handler - * goes live - */ - -class HttpRequestRouter -{ -public: - typedef std::function<void(HttpRouterRequest&)> HandlerFunc_t; - - /** - * @brief Add pattern which can be referenced by name, commonly used for URL components - * @param Id String used to identify patterns for replacement - * @param Regex String which will replace the Id string in any registered URL paths - */ - void AddPattern(const char* Id, const char* Regex); - - /** - * @brief Register a an endpoint handler for the given route - * @param Regex Regular expression used to match the handler to a request. This may - * contain pattern aliases registered via AddPattern - * @param HandlerFunc Handler function to call for any matching request - * @param SupportedVerbs Supported HTTP verbs for this handler - */ - void RegisterRoute(const char* Regex, HandlerFunc_t&& HandlerFunc, HttpVerb SupportedVerbs); - /** - * @brief Register CbPackage endpoint handler - * @param Regex Regular expression used to match the handler to a request. This may - * contain pattern aliases registered via AddPattern - * @param Handler Package handler instance - */ - void RegisterRoute(const char* Regex, PackageEndpointHandler& Handler); - - void ProcessRegexSubstitutions(const char* Regex, StringBuilderBase& ExpandedRegex); - - /** - * @brief HTTP request handling function - this should be called to route the - * request to a registered handler - * @param Request Request to route to a handler - * @return Function returns true if the request was routed successfully - */ - bool HandleRequest(zen::HttpServerRequest& Request); - -private: - struct HandlerEntry - { - HandlerEntry(const char* Regex, HttpVerb SupportedVerbs, HandlerFunc_t&& Handler, const char* Pattern) - : RegEx(Regex, std::regex::icase | std::regex::ECMAScript) - , Verbs(SupportedVerbs) - , Handler(std::move(Handler)) - , Pattern(Pattern) - { - } - - ~HandlerEntry() = default; - - std::regex RegEx; - HttpVerb Verbs; - HandlerFunc_t Handler; - const char* Pattern; - - private: - HandlerEntry& operator=(const HandlerEntry&) = delete; - HandlerEntry(const HandlerEntry&) = delete; - }; - - std::list<HandlerEntry> m_Handlers; - std::unordered_map<std::string, std::string> m_PatternMap; -}; - -////////////////////////////////////////////////////////////////////////// -// -// HTTP Client -// - -class HttpClient -{ -}; - -} // namespace zen - -void http_forcelink(); // internal diff --git a/zencore/iothreadpool.cpp b/zencore/iothreadpool.cpp deleted file mode 100644 index 4ed81d7a2..000000000 --- a/zencore/iothreadpool.cpp +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright Epic Games, Inc. All Rights Reserved. - -#include "iothreadpool.h" - -namespace zen { - -WinIoThreadPool::WinIoThreadPool(int InThreadCount) -{ - // Thread pool setup - - m_ThreadPool = CreateThreadpool(NULL); - - SetThreadpoolThreadMinimum(m_ThreadPool, InThreadCount); - SetThreadpoolThreadMaximum(m_ThreadPool, InThreadCount * 2); - - InitializeThreadpoolEnvironment(&m_CallbackEnvironment); - - m_CleanupGroup = CreateThreadpoolCleanupGroup(); - - SetThreadpoolCallbackPool(&m_CallbackEnvironment, m_ThreadPool); - - SetThreadpoolCallbackCleanupGroup(&m_CallbackEnvironment, m_CleanupGroup, NULL); -} - -WinIoThreadPool::~WinIoThreadPool() -{ - CloseThreadpool(m_ThreadPool); -} - -void -WinIoThreadPool::CreateIocp(HANDLE IoHandle, PTP_WIN32_IO_CALLBACK Callback, void* Context) -{ - m_ThreadPoolIo = CreateThreadpoolIo(IoHandle, Callback, Context, &m_CallbackEnvironment); -} - -} // namespace zen diff --git a/zencore/iothreadpool.h b/zencore/iothreadpool.h deleted file mode 100644 index f64868540..000000000 --- a/zencore/iothreadpool.h +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright Epic Games, Inc. All Rights Reserved. - -#pragma once - -#include <zencore/windows.h> - -namespace zen { - -////////////////////////////////////////////////////////////////////////// -// -// Thread pool. Implemented in terms of Windows thread pool right now, will -// need a cross-platform implementation eventually -// - -class WinIoThreadPool -{ -public: - WinIoThreadPool(int InThreadCount); - ~WinIoThreadPool(); - - void CreateIocp(HANDLE IoHandle, PTP_WIN32_IO_CALLBACK Callback, void* Context); - inline PTP_IO Iocp() const { return m_ThreadPoolIo; } - -private: - PTP_POOL m_ThreadPool = nullptr; - PTP_CLEANUP_GROUP m_CleanupGroup = nullptr; - PTP_IO m_ThreadPoolIo = nullptr; - TP_CALLBACK_ENVIRON m_CallbackEnvironment; -}; - -} // namespace zen diff --git a/zencore/zencore.vcxproj b/zencore/zencore.vcxproj index ef83e95f1..4b5bba185 100644 --- a/zencore/zencore.vcxproj +++ b/zencore/zencore.vcxproj @@ -112,7 +112,6 @@ </Lib> </ItemDefinitionGroup> <ItemGroup> - <ClInclude Include="httpsys.h" /> <ClInclude Include="include\zencore\atomic.h" /> <ClInclude Include="include\zencore\blake3.h" /> <ClInclude Include="include\zencore\compositebuffer.h" /> @@ -123,8 +122,6 @@ <ClInclude Include="include\zencore\compress.h" /> <ClInclude Include="include\zencore\filesystem.h" /> <ClInclude Include="include\zencore\fmtutils.h" /> - <ClInclude Include="include\zencore\httpclient.h" /> - <ClInclude Include="include\zencore\httpserver.h" /> <ClInclude Include="include\zencore\intmath.h" /> <ClInclude Include="include\zencore\iohash.h" /> <ClInclude Include="include\zencore\logging.h" /> @@ -155,7 +152,6 @@ <ClInclude Include="include\zencore\windows.h" /> <ClInclude Include="include\zencore\xxhash.h" /> <ClInclude Include="include\zencore\zencore.h" /> - <ClInclude Include="iothreadpool.h" /> </ItemGroup> <ItemGroup> <ClCompile Include="blake3.cpp" /> @@ -164,11 +160,7 @@ <ClCompile Include="crc32.cpp" /> <ClCompile Include="except.cpp" /> <ClCompile Include="filesystem.cpp" /> - <ClCompile Include="httpclient.cpp" /> - <ClCompile Include="httpserver.cpp" /> - <ClCompile Include="httpsys.cpp" /> <ClCompile Include="iohash.cpp" /> - <ClCompile Include="iothreadpool.cpp" /> <ClCompile Include="logging.cpp" /> <ClCompile Include="md5.cpp" /> <ClCompile Include="memory.cpp" /> diff --git a/zencore/zencore.vcxproj.filters b/zencore/zencore.vcxproj.filters index 519ee0ce1..70c1cfb01 100644 --- a/zencore/zencore.vcxproj.filters +++ b/zencore/zencore.vcxproj.filters @@ -21,7 +21,6 @@ <ClInclude Include="include\zencore\enumflags.h" /> <ClInclude Include="include\zencore\except.h" /> <ClInclude Include="include\zencore\filesystem.h" /> - <ClInclude Include="include\zencore\httpserver.h" /> <ClInclude Include="include\zencore\refcount.h" /> <ClInclude Include="include\zencore\memory.h" /> <ClInclude Include="include\zencore\windows.h" /> @@ -31,11 +30,9 @@ <ClInclude Include="include\zencore\compactbinarybuilder.h" /> <ClInclude Include="include\zencore\compactbinarypackage.h" /> <ClInclude Include="include\zencore\compactbinaryvalidation.h" /> - <ClInclude Include="include\zencore\httpclient.h" /> <ClInclude Include="include\zencore\md5.h" /> <ClInclude Include="include\zencore\fmtutils.h" /> <ClInclude Include="include\zencore\xxhash.h" /> - <ClInclude Include="iothreadpool.h" /> <ClInclude Include="include\zencore\varint.h" /> <ClInclude Include="include\zencore\endian.h" /> <ClInclude Include="include\zencore\compositebuffer.h" /> @@ -44,7 +41,6 @@ <ClInclude Include="include\zencore\prewindows.h" /> <ClInclude Include="include\zencore\postwindows.h" /> <ClInclude Include="include\zencore\logging.h" /> - <ClInclude Include="httpsys.h" /> </ItemGroup> <ItemGroup> <ClCompile Include="snapshot_manifest.cpp" /> @@ -54,7 +50,6 @@ <ClCompile Include="uid.cpp" /> <ClCompile Include="blake3.cpp" /> <ClCompile Include="filesystem.cpp" /> - <ClCompile Include="httpserver.cpp" /> <ClCompile Include="memory.cpp" /> <ClCompile Include="refcount.cpp" /> <ClCompile Include="stats.cpp" /> @@ -69,16 +64,13 @@ <ClCompile Include="compactbinarybuilder.cpp" /> <ClCompile Include="compactbinarypackage.cpp" /> <ClCompile Include="compactbinaryvalidation.cpp" /> - <ClCompile Include="httpclient.cpp" /> <ClCompile Include="md5.cpp" /> <ClCompile Include="except.cpp" /> <ClCompile Include="xxhash.cpp" /> - <ClCompile Include="iothreadpool.cpp" /> <ClCompile Include="compress.cpp" /> <ClCompile Include="compositebuffer.cpp" /> <ClCompile Include="crc32.cpp" /> <ClCompile Include="logging.cpp" /> - <ClCompile Include="httpsys.cpp" /> </ItemGroup> <ItemGroup> <Filter Include="CAS"> |