aboutsummaryrefslogtreecommitdiff
path: root/src/zenhttp/servers/httpsys.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/zenhttp/servers/httpsys.cpp')
-rw-r--r--src/zenhttp/servers/httpsys.cpp119
1 files changed, 94 insertions, 25 deletions
diff --git a/src/zenhttp/servers/httpsys.cpp b/src/zenhttp/servers/httpsys.cpp
index 5cd273c40..95d83911d 100644
--- a/src/zenhttp/servers/httpsys.cpp
+++ b/src/zenhttp/servers/httpsys.cpp
@@ -9,11 +9,14 @@
#include <zencore/filesystem.h>
#include <zencore/fmtutils.h>
#include <zencore/logging.h>
+#include <zencore/memory/llm.h>
#include <zencore/scopeguard.h>
#include <zencore/string.h>
#include <zencore/timer.h>
#include <zencore/trace.h>
-#include <zenutil/packageformat.h>
+#include <zenhttp/packageformat.h>
+
+#include <EASTL/fixed_vector.h>
#if ZEN_WITH_HTTPSYS
# define _WINSOCKAPI_
@@ -25,6 +28,14 @@
namespace zen {
+const FLLMTag&
+GetHttpsysTag()
+{
+ static FLLMTag HttpsysTag("httpsys");
+
+ return HttpsysTag;
+}
+
/**
* @brief Windows implementation of HTTP server based on http.sys
*
@@ -372,14 +383,14 @@ public:
void SuppressResponseBody(); // typically used for HEAD requests
private:
- std::vector<HTTP_DATA_CHUNK> m_HttpDataChunks;
- uint64_t m_TotalDataSize = 0; // Sum of all chunk sizes
- uint16_t m_ResponseCode = 0;
- uint32_t m_NextDataChunkOffset = 0; // Cursor used for very large chunk lists
- uint32_t m_RemainingChunkCount = 0; // Backlog for multi-call sends
- bool m_IsInitialResponse = true;
- HttpContentType m_ContentType = HttpContentType::kBinary;
- std::vector<IoBuffer> m_DataBuffers;
+ eastl::fixed_vector<HTTP_DATA_CHUNK, 16> m_HttpDataChunks;
+ uint64_t m_TotalDataSize = 0; // Sum of all chunk sizes
+ uint16_t m_ResponseCode = 0;
+ uint32_t m_NextDataChunkOffset = 0; // Cursor used for very large chunk lists
+ uint32_t m_RemainingChunkCount = 0; // Backlog for multi-call sends
+ bool m_IsInitialResponse = true;
+ HttpContentType m_ContentType = HttpContentType::kBinary;
+ eastl::fixed_vector<IoBuffer, 16> m_DataBuffers;
void InitializeForPayload(uint16_t ResponseCode, std::span<IoBuffer> Blobs);
};
@@ -524,7 +535,14 @@ HttpMessageResponseRequest::HandleCompletion(ULONG IoResult, ULONG_PTR NumberOfB
if (IoResult != NO_ERROR)
{
- ZEN_WARN("response aborted due to error: '{}'", GetSystemErrorAsString(IoResult));
+ ZEN_WARN("response '{}' ({}) aborted after transfering '{}', {} out of {} bytes, reason: {} ({})",
+ ReasonStringForHttpResultCode(m_ResponseCode),
+ m_ResponseCode,
+ ToString(m_ContentType),
+ NumberOfBytesTransferred,
+ m_TotalDataSize,
+ GetSystemErrorAsString(IoResult),
+ IoResult);
// if one transmit failed there's really no need to go on
return nullptr;
@@ -673,7 +691,7 @@ HttpMessageResponseRequest::IssueRequest(std::error_code& ErrorCode)
);
}
- auto EmitReponseDetails = [&](StringBuilderBase& ResponseDetails) -> void {
+ auto EmitResponseDetails = [&](StringBuilderBase& ResponseDetails) -> void {
for (int i = 0; i < ThisRequestChunkCount; ++i)
{
const HTTP_DATA_CHUNK Chunk = m_HttpDataChunks[ThisRequestChunkOffset + i];
@@ -756,7 +774,7 @@ HttpMessageResponseRequest::IssueRequest(std::error_code& ErrorCode)
// Emit diagnostics
ExtendableStringBuilder<256> ResponseDetails;
- EmitReponseDetails(ResponseDetails);
+ EmitResponseDetails(ResponseDetails);
ZEN_WARN("failed to send HTTP response (error {}: '{}'), request URL: '{}', ({}.{}) response: {}",
SendResult,
@@ -817,7 +835,7 @@ HttpAsyncWorkRequest::IssueRequest(std::error_code& ErrorCode)
ZEN_TRACE_CPU("httpsys::AsyncWork::IssueRequest");
ErrorCode.clear();
- Transaction().Server().WorkPool().ScheduleWork(m_WorkItem);
+ Transaction().Server().WorkPool().ScheduleWork(m_WorkItem, WorkerThreadPool::EMode::EnableBacklog);
}
HttpSysRequestHandler*
@@ -836,6 +854,8 @@ HttpAsyncWorkRequest::HandleCompletion(ULONG IoResult, ULONG_PTR NumberOfBytesTr
void
HttpAsyncWorkRequest::AsyncWorkItem::Execute()
{
+ ZEN_MEMSCOPE(GetHttpsysTag());
+
ZEN_TRACE_CPU("httpsys::async_execute");
try
@@ -873,10 +893,15 @@ HttpAsyncWorkRequest::AsyncWorkItem::Execute()
new HttpMessageResponseRequest(Tx, 500, "Response generated but no request handler scheduled"sv));
}
}
- catch (std::exception& Ex)
+ catch (const AssertException& AssertEx)
{
return (void)Tx.IssueNextRequest(
- new HttpMessageResponseRequest(Tx, 500, fmt::format("Exception thrown in async work: '{}'", Ex.what())));
+ new HttpMessageResponseRequest(Tx, 500, fmt::format("Assert thrown in async work: '{}", AssertEx.FullDescription())));
+ }
+ catch (const std::exception& Ex)
+ {
+ return (void)Tx.IssueNextRequest(
+ new HttpMessageResponseRequest(Tx, 500, fmt::format("Exception thrown in async work: {}", Ex.what())));
}
}
@@ -896,6 +921,8 @@ HttpSysServer::HttpSysServer(const HttpSysConfig& InConfig)
, m_IsAsyncResponseEnabled(InConfig.IsAsyncResponseEnabled)
, m_InitialConfig(InConfig)
{
+ ZEN_MEMSCOPE(GetHttpsysTag());
+
// Initialize thread pool
int MinThreadCount;
@@ -971,6 +998,8 @@ HttpSysServer::Close()
int
HttpSysServer::InitializeServer(int BasePort)
{
+ ZEN_MEMSCOPE(GetHttpsysTag());
+
using namespace std::literals;
WideStringBuilder<64> WildcardUrlPath;
@@ -1215,6 +1244,8 @@ HttpSysServer::Cleanup()
WorkerThreadPool&
HttpSysServer::WorkPool()
{
+ ZEN_MEMSCOPE(GetHttpsysTag());
+
if (!m_AsyncWorkPool)
{
RwLock::ExclusiveLockScope _(m_AsyncWorkPoolInitLock);
@@ -1299,6 +1330,8 @@ HttpSysServer::IssueNewRequestMaybe()
return;
}
+ ZEN_MEMSCOPE(GetHttpsysTag());
+
std::unique_ptr<HttpSysTransaction> Request = std::make_unique<HttpSysTransaction>(*this);
std::error_code ErrorCode;
@@ -1322,6 +1355,8 @@ HttpSysServer::IssueNewRequestMaybe()
void
HttpSysServer::RegisterService(const char* UrlPath, HttpService& Service)
{
+ ZEN_MEMSCOPE(GetHttpsysTag());
+
if (UrlPath[0] == '/')
{
++UrlPath;
@@ -1483,11 +1518,15 @@ HttpSysTransaction::IssueNextRequest(HttpSysRequestHandler* NewCompletionHandler
return true;
}
- ZEN_WARN("IssueRequest() failed: '{}'", ErrorCode.message());
+ ZEN_WARN("IssueRequest() failed: {}", ErrorCode.message());
+ }
+ catch (const AssertException& AssertEx)
+ {
+ ZEN_ERROR("Assert thrown in IssueNextRequest(): {}", AssertEx.FullDescription());
}
- catch (std::exception& Ex)
+ catch (const std::exception& Ex)
{
- ZEN_ERROR("exception caught in IssueNextRequest(): '{}'", Ex.what());
+ ZEN_ERROR("exception caught in IssueNextRequest(): {}", Ex.what());
}
// something went wrong, no request is pending
@@ -1659,7 +1698,7 @@ HttpSysServerRequest::ParseSessionId() const
{
if (Header.RawValueLength == Oid::StringLength)
{
- return Oid::FromHexString({Header.pRawValue, Header.RawValueLength});
+ return Oid::TryFromHexString({Header.pRawValue, Header.RawValueLength});
}
}
}
@@ -1698,6 +1737,8 @@ HttpSysServerRequest::ReadPayload()
void
HttpSysServerRequest::WriteResponse(HttpResponseCode ResponseCode)
{
+ ZEN_MEMSCOPE(GetHttpsysTag());
+
ZEN_ASSERT(IsHandled() == false);
auto Response = new HttpMessageResponseRequest(m_HttpTx, (uint16_t)ResponseCode);
@@ -1715,6 +1756,8 @@ HttpSysServerRequest::WriteResponse(HttpResponseCode ResponseCode)
void
HttpSysServerRequest::WriteResponse(HttpResponseCode ResponseCode, HttpContentType ContentType, std::span<IoBuffer> Blobs)
{
+ ZEN_MEMSCOPE(GetHttpsysTag());
+
ZEN_ASSERT(IsHandled() == false);
auto Response = new HttpMessageResponseRequest(m_HttpTx, (uint16_t)ResponseCode, ContentType, Blobs);
@@ -1732,6 +1775,8 @@ HttpSysServerRequest::WriteResponse(HttpResponseCode ResponseCode, HttpContentTy
void
HttpSysServerRequest::WriteResponse(HttpResponseCode ResponseCode, HttpContentType ContentType, std::u8string_view ResponseString)
{
+ ZEN_MEMSCOPE(GetHttpsysTag());
+
ZEN_ASSERT(IsHandled() == false);
auto Response =
@@ -1750,6 +1795,8 @@ HttpSysServerRequest::WriteResponse(HttpResponseCode ResponseCode, HttpContentTy
void
HttpSysServerRequest::WriteResponseAsync(std::function<void(HttpServerRequest&)>&& ContinuationHandler)
{
+ ZEN_MEMSCOPE(GetHttpsysTag());
+
if (m_HttpTx.Server().IsAsyncResponseEnabled())
{
m_NextCompletionHandler = new HttpAsyncWorkRequest(m_HttpTx, std::move(ContinuationHandler));
@@ -1826,7 +1873,17 @@ InitialRequestHandler::IssueRequest(std::error_code& ErrorCode)
ErrorCode = MakeErrorCode(HttpApiResult);
- ZEN_WARN("HttpReceiveHttpRequest failed, error: '{}'", ErrorCode.message());
+ if (IsInitialRequest())
+ {
+ ZEN_WARN("initial HttpReceiveHttpRequest failed, error: {}", ErrorCode.message());
+ }
+ else
+ {
+ ZEN_WARN("HttpReceiveHttpRequest (offset: {}, content-length: {}) failed, error: {}",
+ m_CurrentPayloadOffset,
+ m_PayloadBuffer.GetSize(),
+ ErrorCode.message());
+ }
return;
}
@@ -1837,6 +1894,8 @@ InitialRequestHandler::IssueRequest(std::error_code& ErrorCode)
HttpSysRequestHandler*
InitialRequestHandler::HandleCompletion(ULONG IoResult, ULONG_PTR NumberOfBytesTransferred)
{
+ ZEN_MEMSCOPE(GetHttpsysTag());
+
auto _ = MakeGuard([&] { m_IsInitialRequest = false; });
switch (IoResult)
@@ -1985,23 +2044,28 @@ InitialRequestHandler::HandleCompletion(ULONG IoResult, ULONG_PTR NumberOfBytesT
// Unable to route
return new HttpMessageResponseRequest(Transaction(), 404, "No suitable route found"sv);
}
- catch (std::system_error& SystemError)
+ catch (const AssertException& AssertEx)
+ {
+ ZEN_ERROR("Caught assert exception while handling request: {}", AssertEx.FullDescription());
+ return new HttpMessageResponseRequest(Transaction(), (uint16_t)HttpResponseCode::InternalServerError, AssertEx.FullDescription());
+ }
+ catch (const std::system_error& SystemError)
{
if (IsOOM(SystemError.code()) || IsOOD(SystemError.code()))
{
return new HttpMessageResponseRequest(Transaction(), (uint16_t)HttpResponseCode::InsufficientStorage, SystemError.what());
}
- ZEN_ERROR("Caught system error exception while handling request: {}", SystemError.what());
+ ZEN_WARN("Caught system error exception while handling request: {}. ({})", SystemError.what(), SystemError.code().value());
return new HttpMessageResponseRequest(Transaction(), (uint16_t)HttpResponseCode::InternalServerError, SystemError.what());
}
- catch (std::bad_alloc& BadAlloc)
+ catch (const std::bad_alloc& BadAlloc)
{
return new HttpMessageResponseRequest(Transaction(), (uint16_t)HttpResponseCode::InsufficientStorage, BadAlloc.what());
}
- catch (std::exception& ex)
+ catch (const std::exception& ex)
{
- ZEN_ERROR("Caught exception while handling request: '{}'", ex.what());
+ ZEN_WARN("Caught exception while handling request: '{}'", ex.what());
return new HttpMessageResponseRequest(Transaction(), (uint16_t)HttpResponseCode::InternalServerError, ex.what());
}
}
@@ -2014,6 +2078,8 @@ InitialRequestHandler::HandleCompletion(ULONG IoResult, ULONG_PTR NumberOfBytesT
int
HttpSysServer::Initialize(int BasePort, std::filesystem::path DataDir)
{
+ ZEN_TRACE_CPU("HttpSysServer::Initialize");
+
ZEN_UNUSED(DataDir);
if (int EffectivePort = InitializeServer(BasePort))
{
@@ -2042,6 +2108,9 @@ HttpSysServer::RegisterService(HttpService& Service)
Ref<HttpServer>
CreateHttpSysServer(HttpSysConfig Config)
{
+ ZEN_TRACE_CPU("CreateHttpSysServer");
+ ZEN_MEMSCOPE(GetHttpsysTag());
+
return Ref<HttpServer>(new HttpSysServer(Config));
}