diff options
| author | Stefan Boberg <[email protected]> | 2021-09-08 21:40:10 +0200 |
|---|---|---|
| committer | Stefan Boberg <[email protected]> | 2021-09-08 21:40:10 +0200 |
| commit | cd30f71c241e4c62448566580cca4773df17035f (patch) | |
| tree | ae52528bfdf4e184b58d900d2985f803cdee7906 /zencore/httpserver.cpp | |
| parent | Basic http tests, needs a lot more tests to exercise more functionality (diff) | |
| download | zen-cd30f71c241e4c62448566580cca4773df17035f.tar.xz zen-cd30f71c241e4c62448566580cca4773df17035f.zip | |
Restructuring HTTP server implementation to better (completely asynchronously) deal with large requests. Also preparing to introduce new endpoint handlers and multiple server implementations (i.e besides http.sys)
Diffstat (limited to 'zencore/httpserver.cpp')
| -rw-r--r-- | zencore/httpserver.cpp | 459 |
1 files changed, 265 insertions, 194 deletions
diff --git a/zencore/httpserver.cpp b/zencore/httpserver.cpp index d7e6a875f..a9096b99b 100644 --- a/zencore/httpserver.cpp +++ b/zencore/httpserver.cpp @@ -481,21 +481,55 @@ HttpServerRequest::ReadPayloadPackage() #if ZEN_PLATFORM_WINDOWS class HttpSysServer; -class HttpTransaction; +class HttpSysTransaction; +class HttpMessageResponseRequest; class HttpSysRequestHandler { public: - HttpSysRequestHandler(HttpTransaction& InRequest) : m_Request(InRequest) {} + HttpSysRequestHandler(HttpSysTransaction& InRequest) : m_Request(InRequest) {} virtual ~HttpSysRequestHandler() = default; virtual void IssueRequest() = 0; virtual HttpSysRequestHandler* HandleCompletion(ULONG IoResult, ULONG_PTR NumberOfBytesTransferred) = 0; - HttpTransaction& Transaction() { return m_Request; } + HttpSysTransaction& Transaction() { return m_Request; } private: - HttpTransaction& m_Request; // Outermost HTTP transaction object + 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 @@ -503,12 +537,12 @@ private: There will be an instance of this per pending and in-flight HTTP transaction */ -class HttpTransaction +class HttpSysTransaction { public: - HttpTransaction(HttpSysServer& Server) : m_HttpServer(Server), m_HttpHandler(&m_InitialHttpHandler) {} + HttpSysTransaction(HttpSysServer& Server) : m_HttpServer(Server), m_HttpHandler(&m_InitialHttpHandler) {} - virtual ~HttpTransaction() {} + virtual ~HttpSysTransaction() {} enum class Status { @@ -533,16 +567,15 @@ public: // than one thread at any given moment. This means we need to be careful about what // happens in here - HttpTransaction* Transaction = CONTAINING_RECORD(pOverlapped, HttpTransaction, m_HttpOverlapped); + HttpSysTransaction* Transaction = CONTAINING_RECORD(pOverlapped, HttpSysTransaction, m_HttpOverlapped); - if (Transaction->HandleCompletion(IoResult, NumberOfBytesTransferred) == HttpTransaction::Status::kDone) + if (Transaction->HandleCompletion(IoResult, NumberOfBytesTransferred) == HttpSysTransaction::Status::kDone) { delete Transaction; } } - void IssueInitialRequest(); - + void IssueInitialRequest(); PTP_IO Iocp(); HANDLE RequestQueueHandle(); inline OVERLAPPED* Overlapped() { return &m_HttpOverlapped; } @@ -557,31 +590,41 @@ protected: RwLock m_Lock; private: - struct InitialRequestHandler : public HttpSysRequestHandler - { - inline PHTTP_REQUEST HttpRequest() { return (PHTTP_REQUEST)m_RequestBuffer; } - inline uint32_t RequestBufferSize() const { return sizeof m_RequestBuffer; } + InitialRequestHandler m_InitialHttpHandler{*this}; +}; - InitialRequestHandler(HttpTransaction& InRequest) : HttpSysRequestHandler(InRequest) {} - ~InitialRequestHandler() {} +////////////////////////////////////////////////////////////////////////// - virtual void IssueRequest() override; - virtual HttpSysRequestHandler* HandleCompletion(ULONG IoResult, ULONG_PTR NumberOfBytesTransferred) override; +class HttpPayloadReadRequest : public HttpSysRequestHandler +{ +public: + HttpPayloadReadRequest(HttpSysTransaction& InRequest) : HttpSysRequestHandler(InRequest) {} - PHTTP_REQUEST m_HttpRequestPtr = (HTTP_REQUEST*)(m_RequestBuffer); - UCHAR m_RequestBuffer[16384 + sizeof(HTTP_REQUEST)]; - } m_InitialHttpHandler{*this}; + 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(HttpTransaction& InRequest, uint16_t ResponseCode); - HttpMessageResponseRequest(HttpTransaction& InRequest, uint16_t ResponseCode, const char* Message); - HttpMessageResponseRequest(HttpTransaction& InRequest, uint16_t ResponseCode, const void* Payload, size_t PayloadSize); - HttpMessageResponseRequest(HttpTransaction& InRequest, uint16_t ResponseCode, std::span<IoBuffer> Blobs); + 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; @@ -603,14 +646,15 @@ private: std::vector<IoBuffer> m_DataBuffers; }; -HttpMessageResponseRequest::HttpMessageResponseRequest(HttpTransaction& InRequest, uint16_t ResponseCode) : HttpSysRequestHandler(InRequest) +HttpMessageResponseRequest::HttpMessageResponseRequest(HttpSysTransaction& InRequest, uint16_t ResponseCode) +: HttpSysRequestHandler(InRequest) { std::array<IoBuffer, 0> buffers; Initialize(ResponseCode, buffers); } -HttpMessageResponseRequest::HttpMessageResponseRequest(HttpTransaction& InRequest, uint16_t ResponseCode, const char* Message) +HttpMessageResponseRequest::HttpMessageResponseRequest(HttpSysTransaction& InRequest, uint16_t ResponseCode, const char* Message) : HttpSysRequestHandler(InRequest) { IoBuffer MessageBuffer(IoBuffer::Wrap, Message, strlen(Message)); @@ -619,10 +663,10 @@ HttpMessageResponseRequest::HttpMessageResponseRequest(HttpTransaction& InReques Initialize(ResponseCode, buffers); } -HttpMessageResponseRequest::HttpMessageResponseRequest(HttpTransaction& InRequest, - uint16_t ResponseCode, - const void* Payload, - size_t PayloadSize) +HttpMessageResponseRequest::HttpMessageResponseRequest(HttpSysTransaction& InRequest, + uint16_t ResponseCode, + const void* Payload, + size_t PayloadSize) : HttpSysRequestHandler(InRequest) { IoBuffer MessageBuffer(IoBuffer::Wrap, Payload, PayloadSize); @@ -631,7 +675,7 @@ HttpMessageResponseRequest::HttpMessageResponseRequest(HttpTransaction& InReques Initialize(ResponseCode, buffers); } -HttpMessageResponseRequest::HttpMessageResponseRequest(HttpTransaction& InRequest, uint16_t ResponseCode, std::span<IoBuffer> Blobs) +HttpMessageResponseRequest::HttpMessageResponseRequest(HttpSysTransaction& InRequest, uint16_t ResponseCode, std::span<IoBuffer> Blobs) : HttpSysRequestHandler(InRequest) { Initialize(ResponseCode, Blobs); @@ -708,7 +752,9 @@ HttpMessageResponseRequest::HandleCompletion(ULONG IoResult, ULONG_PTR NumberOfB ZEN_UNUSED(IoResult); if (m_RemainingChunkCount == 0) + { return nullptr; // All done + } return this; } @@ -716,7 +762,7 @@ HttpMessageResponseRequest::HandleCompletion(ULONG IoResult, ULONG_PTR NumberOfB void HttpMessageResponseRequest::IssueRequest() { - HttpTransaction& Tx = Transaction(); + HttpSysTransaction& Tx = Transaction(); HTTP_REQUEST* const HttpReq = Tx.HttpRequest(); PTP_IO const Iocp = Tx.Iocp(); @@ -828,7 +874,7 @@ HttpMessageResponseRequest::IssueRequest() class HttpSysServer { - friend class HttpTransaction; + friend class HttpSysTransaction; public: HttpSysServer(WinIoThreadPool& InThreadPool); @@ -945,7 +991,7 @@ HttpSysServer::Initialize(const wchar_t* UrlPath) // Create I/O completion port - m_ThreadPool.CreateIocp(m_RequestQueueHandle, HttpTransaction::IoCompletionCallback, this); + m_ThreadPool.CreateIocp(m_RequestQueueHandle, HttpSysTransaction::IoCompletionCallback, this); // Check result! } @@ -1015,7 +1061,7 @@ HttpSysServer::IssueNewRequestMaybe() return; } - std::unique_ptr<HttpTransaction> Request = std::make_unique<HttpTransaction>(*this); + std::unique_ptr<HttpSysTransaction> Request = std::make_unique<HttpSysTransaction>(*this); Request->IssueInitialRequest(); @@ -1083,227 +1129,235 @@ HttpSysServer::RemoveEndpoint(const char* UrlPath, HttpService& Service) ////////////////////////////////////////////////////////////////////////// -class HttpSysServerRequest : public HttpServerRequest +HttpSysServerRequest::HttpSysServerRequest(HttpSysTransaction& Tx, HttpService& Service) : m_IsInitialized(true), m_HttpTx(Tx) { -public: - HttpSysServerRequest(HttpTransaction& Tx, HttpService& Service) : m_HttpTx(Tx) - { - PHTTP_REQUEST HttpRequestPtr = Tx.HttpRequest(); + PHTTP_REQUEST HttpRequestPtr = Tx.HttpRequest(); - const int PrefixLength = Service.UriPrefixLength(); - const int AbsPathLength = HttpRequestPtr->CookedUrl.AbsPathLength / sizeof(char16_t); + 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 + 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(); - } + 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; + if (auto QueryStringLength = HttpRequestPtr->CookedUrl.QueryStringLength) + { + --QueryStringLength; - WideToUtf8({(char16_t*)(HttpRequestPtr->CookedUrl.pQueryString) + 1, QueryStringLength / sizeof(char16_t)}, m_QueryString); - } - else - { - m_QueryString.Reset(); - } + 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; - } + switch (HttpRequestPtr->Verb) + { + case HttpVerbOPTIONS: + m_Verb = HttpVerb::kOptions; + 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); + case HttpVerbGET: + m_Verb = HttpVerb::kGet; + break; - const HTTP_KNOWN_HEADER& CtHdr = HttpRequestPtr->Headers.KnownHeaders[HttpHeaderContentType]; - m_ContentType = MapContentType({CtHdr.pRawValue, CtHdr.RawValueLength}); - } + case HttpVerbHEAD: + m_Verb = HttpVerb::kHead; + break; - ~HttpSysServerRequest() {} + case HttpVerbPOST: + m_Verb = HttpVerb::kPost; + break; - virtual IoBuffer ReadPayload() override - { - // This is presently synchronous for simplicity, but we - // need to implement an asynchronous version also + case HttpVerbPUT: + m_Verb = HttpVerb::kPut; + break; - HTTP_REQUEST* const HttpReq = m_HttpTx.HttpRequest(); + case HttpVerbDELETE: + m_Verb = HttpVerb::kDelete; + break; - IoBuffer PayloadBuffer(m_ContentLength); + case HttpVerbCOPY: + m_Verb = HttpVerb::kCopy; + break; - HttpContentType ContentType = RequestContentType(); - PayloadBuffer.SetContentType(ContentType); + default: + // TODO: invalid request? + m_Verb = (HttpVerb)0; + break; + } - uint64_t BytesToRead = m_ContentLength; + 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); - uint8_t* ReadPointer = reinterpret_cast<uint8_t*>(PayloadBuffer.MutableData()); + const HTTP_KNOWN_HEADER& CtHdr = HttpRequestPtr->Headers.KnownHeaders[HttpHeaderContentType]; + m_ContentType = MapContentType({CtHdr.pRawValue, CtHdr.RawValueLength}); +} - // First deal with any payload which has already been copied - // into our request buffer +void +HttpSysServerRequest::ReadPayload(std::function<void(HttpServerRequest&, IoBuffer)>&& CompletionHandler) +{ + ZEN_UNUSED(CompletionHandler); +} - const int EntityChunkCount = HttpReq->EntityChunkCount; +IoBuffer +HttpSysServerRequest::ReadPayload() +{ + // This is presently synchronous for simplicity, but we + // need to implement an asynchronous version also - for (int i = 0; i < EntityChunkCount; ++i) - { - HTTP_DATA_CHUNK& EntityChunk = HttpReq->pEntityChunks[i]; + HTTP_REQUEST* const HttpReq = m_HttpTx.HttpRequest(); - ZEN_ASSERT(EntityChunk.DataChunkType == HttpDataChunkFromMemory); + IoBuffer PayloadBuffer(m_ContentLength); - const uint64_t BufferLength = EntityChunk.FromMemory.BufferLength; + HttpContentType ContentType = RequestContentType(); + PayloadBuffer.SetContentType(ContentType); - ZEN_ASSERT(BufferLength <= BytesToRead); + uint64_t BytesToRead = m_ContentLength; - memcpy(ReadPointer, EntityChunk.FromMemory.pBuffer, BufferLength); + uint8_t* ReadPointer = reinterpret_cast<uint8_t*>(PayloadBuffer.MutableData()); - ReadPointer += BufferLength; - BytesToRead -= BufferLength; - } + // First deal with any payload which has already been copied + // into our request buffer - // Call http.sys API to receive the remaining data + const int EntityChunkCount = HttpReq->EntityChunkCount; - static const uint64_t kMaxBytesPerApiCall = 1 * 1024 * 1024; + for (int i = 0; i < EntityChunkCount; ++i) + { + HTTP_DATA_CHUNK& EntityChunk = HttpReq->pEntityChunks[i]; - while (BytesToRead) - { - ULONG BytesRead = 0; + ZEN_ASSERT(EntityChunk.DataChunkType == HttpDataChunkFromMemory); - const uint64_t BytesToReadThisCall = zen::Min(BytesToRead, kMaxBytesPerApiCall); + const uint64_t BufferLength = EntityChunk.FromMemory.BufferLength; - ULONG ApiResult = HttpReceiveRequestEntityBody(m_HttpTx.RequestQueueHandle(), - HttpReq->RequestId, - 0, /* Flags */ - ReadPointer, - gsl::narrow<ULONG>(BytesToReadThisCall), - &BytesRead, - NULL /* Overlapped */ - ); + ZEN_ASSERT(BufferLength <= BytesToRead); - if (ApiResult != NO_ERROR && ApiResult != ERROR_HANDLE_EOF) - { - throw HttpServerException("payload read failed", ApiResult); - } + memcpy(ReadPointer, EntityChunk.FromMemory.pBuffer, BufferLength); - BytesToRead -= BytesRead; - ReadPointer += BytesRead; - } + ReadPointer += BufferLength; + BytesToRead -= BufferLength; + } + if (BytesToRead == 0) + { PayloadBuffer.MakeImmutable(); return PayloadBuffer; } - virtual void WriteResponse(HttpResponse HttpResponseCode) override + // Call http.sys API to receive the remaining data SYNCHRONOUSLY + + static const uint64_t kMaxBytesPerApiCall = 1 * 1024 * 1024; + + while (BytesToRead) { - ZEN_ASSERT(m_IsHandled == false); + ULONG BytesRead = 0; + + const uint64_t BytesToReadThisCall = zen::Min(BytesToRead, kMaxBytesPerApiCall); - m_Response = new HttpMessageResponseRequest(m_HttpTx, (uint16_t)HttpResponseCode); + ULONG ApiResult = HttpReceiveRequestEntityBody(m_HttpTx.RequestQueueHandle(), + HttpReq->RequestId, + 0, /* Flags */ + ReadPointer, + gsl::narrow<ULONG>(BytesToReadThisCall), + &BytesRead, + NULL /* Overlapped */ + ); - if (m_SuppressBody) + if (ApiResult != NO_ERROR && ApiResult != ERROR_HANDLE_EOF) { - m_Response->SuppressResponseBody(); + throw HttpServerException("payload read failed", ApiResult); } - m_IsHandled = true; + BytesToRead -= BytesRead; + ReadPointer += BytesRead; } - virtual void WriteResponse(HttpResponse HttpResponseCode, HttpContentType ContentType, std::span<IoBuffer> Blobs) override - { - ZEN_ASSERT(m_IsHandled == false); - ZEN_UNUSED(ContentType); + PayloadBuffer.MakeImmutable(); - m_Response = new HttpMessageResponseRequest(m_HttpTx, (uint16_t)HttpResponseCode, Blobs); + return PayloadBuffer; +} - if (m_SuppressBody) - { - m_Response->SuppressResponseBody(); - } +void +HttpSysServerRequest::WriteResponse(HttpResponse HttpResponseCode) +{ + ZEN_ASSERT(m_IsHandled == false); + + m_Response = new HttpMessageResponseRequest(m_HttpTx, (uint16_t)HttpResponseCode); - m_IsHandled = true; + if (m_SuppressBody) + { + m_Response->SuppressResponseBody(); } - virtual void WriteResponse(HttpResponse HttpResponseCode, HttpContentType ContentType, std::u8string_view ResponseString) override + 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) { - ZEN_ASSERT(m_IsHandled == false); - ZEN_UNUSED(ContentType); + m_Response->SuppressResponseBody(); + } - m_Response = new HttpMessageResponseRequest(m_HttpTx, (uint16_t)HttpResponseCode, ResponseString.data(), ResponseString.size()); + m_IsHandled = true; +} - if (m_SuppressBody) - { - m_Response->SuppressResponseBody(); - } +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()); - m_IsHandled = true; + if (m_SuppressBody) + { + m_Response->SuppressResponseBody(); } - HttpTransaction& m_HttpTx; - HttpMessageResponseRequest* m_Response = nullptr; -}; + m_IsHandled = true; +} ////////////////////////////////////////////////////////////////////////// PTP_IO -HttpTransaction::Iocp() +HttpSysTransaction::Iocp() { return m_HttpServer.m_ThreadPool.Iocp(); } HANDLE -HttpTransaction::RequestQueueHandle() +HttpSysTransaction::RequestQueueHandle() { return m_HttpServer.m_RequestQueueHandle; } void -HttpTransaction::IssueInitialRequest() +HttpSysTransaction::IssueInitialRequest() { m_InitialHttpHandler.IssueRequest(); } -HttpTransaction::Status -HttpTransaction::HandleCompletion(ULONG IoResult, ULONG_PTR NumberOfBytesTransferred) +HttpSysTransaction::Status +HttpSysTransaction::HandleCompletion(ULONG IoResult, ULONG_PTR NumberOfBytesTransferred) { // We use this to ensure sequential execution of completion handlers // for any given transaction. @@ -1347,6 +1401,7 @@ HttpTransaction::HandleCompletion(ULONG IoResult, ULONG_PTR NumberOfBytesTransfe } } + // Ensure new requests are enqueued m_HttpServer.IssueNewRequestMaybe(); if (RequestPending) @@ -1360,13 +1415,13 @@ HttpTransaction::HandleCompletion(ULONG IoResult, ULONG_PTR NumberOfBytesTransfe ////////////////////////////////////////////////////////////////////////// void -HttpTransaction::InitialRequestHandler::IssueRequest() +InitialRequestHandler::IssueRequest() { PTP_IO Iocp = Transaction().Iocp(); StartThreadpoolIo(Iocp); - HttpTransaction& Tx = Transaction(); + HttpSysTransaction& Tx = Transaction(); HTTP_REQUEST* HttpReq = Tx.HttpRequest(); @@ -1389,14 +1444,14 @@ HttpTransaction::InitialRequestHandler::IssueRequest() // CleanupHttpIoRequest(pIoRequest); - fprintf(stderr, "HttpReceiveHttpRequest failed, error 0x%lx\n", Result); + spdlog::error("HttpReceiveHttpRequest failed, error {:x}", Result); return; } } HttpSysRequestHandler* -HttpTransaction::InitialRequestHandler::HandleCompletion(ULONG IoResult, ULONG_PTR NumberOfBytesTransferred) +InitialRequestHandler::HandleCompletion(ULONG IoResult, ULONG_PTR NumberOfBytesTransferred) { ZEN_UNUSED(IoResult); ZEN_UNUSED(NumberOfBytesTransferred); @@ -1536,10 +1591,28 @@ HttpRequestRouter::AddPattern(const char* Id, const char* Regex) void HttpRequestRouter::RegisterRoute(const char* Regex, HttpRequestRouter::HandlerFunc_t&& HandlerFunc, HttpVerb SupportedVerbs) { - // Expand patterns + 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;) @@ -1558,13 +1631,13 @@ HttpRequestRouter::RegisterRoute(const char* Regex, HttpRequestRouter::HandlerFu if (auto it = m_PatternMap.find(Pattern); it != m_PatternMap.end()) { - ExpandedRegex.Append(it->second.c_str()); + OutExpandedRegex.Append(it->second.c_str()); } else { // Default to anything goes (or should this just be an error?) - ExpandedRegex.Append("(.+?)"); + OutExpandedRegex.Append("(.+?)"); } // skip ahead @@ -1579,11 +1652,9 @@ HttpRequestRouter::RegisterRoute(const char* Regex, HttpRequestRouter::HandlerFu if (!matched) { - ExpandedRegex.Append(Regex[i++]); + OutExpandedRegex.Append(Regex[i++]); } } - - m_Handlers.emplace_back(ExpandedRegex.c_str(), SupportedVerbs, std::move(HandlerFunc), Regex); } bool |