aboutsummaryrefslogtreecommitdiff
path: root/zencore/httpserver.cpp
diff options
context:
space:
mode:
authorStefan Boberg <[email protected]>2021-09-08 21:40:10 +0200
committerStefan Boberg <[email protected]>2021-09-08 21:40:10 +0200
commitcd30f71c241e4c62448566580cca4773df17035f (patch)
treeae52528bfdf4e184b58d900d2985f803cdee7906 /zencore/httpserver.cpp
parentBasic http tests, needs a lot more tests to exercise more functionality (diff)
downloadzen-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.cpp459
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