diff options
| author | Stefan Boberg <[email protected]> | 2025-10-06 22:33:00 +0200 |
|---|---|---|
| committer | Stefan Boberg <[email protected]> | 2025-10-06 22:33:00 +0200 |
| commit | 1383dbdc563d90c170ab30ba622ee44e2e37e723 (patch) | |
| tree | 59777db60000fe2ab2334f05776fb9ded4ca41fb /src/zenhttp/servers/httpsys.cpp | |
| parent | Merge branch 'main' into sb/rpc-analysis (diff) | |
| parent | 5.7.6 (diff) | |
| download | zen-1383dbdc563d90c170ab30ba622ee44e2e37e723.tar.xz zen-1383dbdc563d90c170ab30ba622ee44e2e37e723.zip | |
Merge remote-tracking branch 'origin/main' into sb/rpc-analysis
Diffstat (limited to 'src/zenhttp/servers/httpsys.cpp')
| -rw-r--r-- | src/zenhttp/servers/httpsys.cpp | 119 |
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)); } |