aboutsummaryrefslogtreecommitdiff
path: root/src/zenhttp/servers
diff options
context:
space:
mode:
authorStefan Boberg <[email protected]>2026-03-06 10:11:51 +0100
committerGitHub Enterprise <[email protected]>2026-03-06 10:11:51 +0100
commit1e731796187ad73b2dee44b48fcecdd487616394 (patch)
tree0ea37769f743ae1fb2eacc37bc8ccfa88ecc0d64 /src/zenhttp/servers
parentfix oidctoken exe lookup check (#811) (diff)
downloadzen-1e731796187ad73b2dee44b48fcecdd487616394.tar.xz
zen-1e731796187ad73b2dee44b48fcecdd487616394.zip
Claude config, some bug fixes (#813)
* Claude config updates * Bug fixes and hardening across `zencore` and `zenhttp`, identified via static analysis. ### zencore - **`ZEN_ASSERT` macro** -- extended to accept an optional string message literal; added `ZEN_ASSERT_MSG_` helper for message formatting. Callers needing runtime fmt-style formatting should use `ZEN_ASSERT_FORMAT`. - **`MpscQueue`** -- fixed `TypeCompatibleStorage` to use a properly-sized `char Storage[sizeof(T)]` array instead of a single `char`; corrected `Data()` to cast `&Storage` rather than `this`; switched cache-line alignment to a fixed constant to avoid GCC's `-Winterference-size` warning. Enabled previously-disabled tests. - **`StringBuilderImpl`** -- initialized `m_Base`/`m_CurPos`/`m_End` to `nullptr`. Fixed `StringCompare` return type (`bool` -> `int`). Fixed `ParseInt` to reject strings with trailing non-numeric characters. Removed deprecated `<codecvt>` include. - **`NiceNumGeneral`** -- replaced `powl()` with integer `IntPow()` to avoid floating-point precision issues. - **`RwLock::ExclusiveLockScope`** -- added move constructor/assignment; initialized `m_Lock` to `nullptr`. - **`Latch::AddCount`** -- fixed variable type (`std::atomic_ptrdiff_t` -> `std::ptrdiff_t` for the return value of `fetch_add`). - **`thread.cpp`** -- fixed Linux `pthread_setname_np` 16-byte name truncation; added null check before dereferencing in `Event::Close()`; fixed `NamedEvent::Close()` to call `close(Fd)` outside the lock region; added null guard in `NamedMutex` destructor; `Sleep()` now returns early for non-positive durations. - **`MD5Stream`** -- was entirely stubbed out (no-op); now correctly calls `MD5Init`/`MD5Update`/`MD5Final`. Fixed `ToHexString` to use the correct string length. Fixed forward declarations. Fixed tests to compare `compare() == 0`. - **`sentryintegration.cpp`** -- guard against null `filename`/`funcname` in spdlog message handler to prevent a crash in `fmt::format`. - **`jobqueue.cpp`** -- fixed lost job ID when `IdGenerator` wraps around zero; fixed raw `Job*` in `RunningJobs` map (potential use-after-free) to `RefPtr<Job>`; fixed range-loop copies; fixed format string typo. - **`trace.cpp`** -- suppress GCC false-positive warnings in third-party `trace.h` include. ### zenhttp - **WebSocket close race** (`wsasio`, `wshttpsys`, `httpwsclient`) -- `m_CloseSent` promoted from `bool` to `std::atomic<bool>`; close check changed to `exchange(true)` to eliminate the check-then-set data race. - **`wsframecodec.cpp`** -- reject WebSocket frames with payload > 256 MB to prevent OOM from malformed/malicious frames. - **`oidc.cpp`** -- URL-encode refresh token and client ID in token requests (`FormUrlEncode`); parse `end_session_endpoint` and `device_authorization_endpoint` from OIDC discovery document. - **`httpclientcommon.cpp`** -- propagate error code from `AppendData` when flushing the cache buffer. - **`httpclient.h`** -- initialize all uninitialized members (`ErrorCode`, `UploadedBytes`, `DownloadedBytes`, `ElapsedSeconds`, `MultipartBoundary` fields). - **`httpserver.h`** -- fix `operator=` return type for `HttpRpcHandler` (missing `&`). - **`packageformat.h`** -- fix `~0u` (32-bit truncation) to `~uint64_t(0)` for a `uint64_t` field. - **`httpparser`** -- initialize `m_RequestVerb` in both declaration and `ResetState()`. - **`httpplugin.cpp`** -- initialize `m_BasePort`; fix format string missing quotes around connection name. - **`httptracer.h`** -- move `#pragma once` before includes. - **`websocket.h`** -- initialize `WebSocketMessage::Opcode`. ### zenserver - **`hubservice.cpp`** -- fix two `ZEN_ASSERT` calls that incorrectly used fmt-style format args; converted to `ZEN_ASSERT_FORMAT`.
Diffstat (limited to 'src/zenhttp/servers')
-rw-r--r--src/zenhttp/servers/httpparser.cpp8
-rw-r--r--src/zenhttp/servers/httpparser.h2
-rw-r--r--src/zenhttp/servers/httpplugin.cpp4
-rw-r--r--src/zenhttp/servers/httptracer.h4
-rw-r--r--src/zenhttp/servers/wsasio.cpp6
-rw-r--r--src/zenhttp/servers/wsasio.h2
-rw-r--r--src/zenhttp/servers/wsframecodec.cpp7
-rw-r--r--src/zenhttp/servers/wshttpsys.cpp6
-rw-r--r--src/zenhttp/servers/wshttpsys.h2
9 files changed, 19 insertions, 22 deletions
diff --git a/src/zenhttp/servers/httpparser.cpp b/src/zenhttp/servers/httpparser.cpp
index 3b1229375..918b55dc6 100644
--- a/src/zenhttp/servers/httpparser.cpp
+++ b/src/zenhttp/servers/httpparser.cpp
@@ -245,13 +245,6 @@ NormalizeUrlPath(std::string_view InUrl, std::string& NormalizedUrl)
NormalizedUrl.reserve(UrlLength);
NormalizedUrl.append(Url, UrlIndex);
}
-
- // NOTE: this check is redundant given the enclosing if,
- // need to verify the intent of this code
- if (!LastCharWasSeparator)
- {
- NormalizedUrl.push_back('/');
- }
}
else if (!NormalizedUrl.empty())
{
@@ -389,6 +382,7 @@ HttpRequestParser::ResetState()
m_UpgradeHeaderIndex = -1;
m_SecWebSocketKeyHeaderIndex = -1;
m_SecWebSocketVersionHeaderIndex = -1;
+ m_RequestVerb = HttpVerb::kGet;
m_Expect100Continue = false;
m_BodyBuffer = {};
m_BodyPosition = 0;
diff --git a/src/zenhttp/servers/httpparser.h b/src/zenhttp/servers/httpparser.h
index d40a5aeb0..23ad9d8fb 100644
--- a/src/zenhttp/servers/httpparser.h
+++ b/src/zenhttp/servers/httpparser.h
@@ -93,7 +93,7 @@ private:
int8_t m_UpgradeHeaderIndex;
int8_t m_SecWebSocketKeyHeaderIndex;
int8_t m_SecWebSocketVersionHeaderIndex;
- HttpVerb m_RequestVerb;
+ HttpVerb m_RequestVerb = HttpVerb::kGet;
std::atomic_bool m_KeepAlive{false};
bool m_Expect100Continue = false;
int m_RequestId = -1;
diff --git a/src/zenhttp/servers/httpplugin.cpp b/src/zenhttp/servers/httpplugin.cpp
index 8564826d6..850dafdca 100644
--- a/src/zenhttp/servers/httpplugin.cpp
+++ b/src/zenhttp/servers/httpplugin.cpp
@@ -123,7 +123,7 @@ struct HttpPluginServerImpl : public HttpPluginServer, TransportServer
bool m_IsRequestLoggingEnabled = false;
LoggerRef m_RequestLog;
std::atomic_uint32_t m_ConnectionIdCounter{0};
- int m_BasePort;
+ int m_BasePort = 0;
HttpServerTracer m_RequestTracer;
@@ -294,7 +294,7 @@ HttpPluginConnectionHandler::Initialize(TransportConnection* Transport, HttpPlug
ConnectionName = "anonymous";
}
- ZEN_LOG_TRACE(m_Server->m_RequestLog, "NEW connection #{} ('')", m_ConnectionId, ConnectionName);
+ ZEN_LOG_TRACE(m_Server->m_RequestLog, "NEW connection #{} ('{}')", m_ConnectionId, ConnectionName);
}
uint32_t
diff --git a/src/zenhttp/servers/httptracer.h b/src/zenhttp/servers/httptracer.h
index da72c79c9..a9a45f162 100644
--- a/src/zenhttp/servers/httptracer.h
+++ b/src/zenhttp/servers/httptracer.h
@@ -1,9 +1,9 @@
// Copyright Epic Games, Inc. All Rights Reserved.
-#include <zenhttp/httpserver.h>
-
#pragma once
+#include <zenhttp/httpserver.h>
+
namespace zen {
/** Helper class for HTTP server implementations
diff --git a/src/zenhttp/servers/wsasio.cpp b/src/zenhttp/servers/wsasio.cpp
index dfc1eac38..3e31b58bc 100644
--- a/src/zenhttp/servers/wsasio.cpp
+++ b/src/zenhttp/servers/wsasio.cpp
@@ -140,9 +140,8 @@ WsAsioConnection::ProcessReceivedData()
}
// Echo close frame back if we haven't sent one yet
- if (!m_CloseSent)
+ if (!m_CloseSent.exchange(true))
{
- m_CloseSent = true;
std::vector<uint8_t> CloseFrame = WsFrameCodec::BuildCloseFrame(Code);
EnqueueWrite(std::move(CloseFrame));
}
@@ -208,9 +207,8 @@ WsAsioConnection::DoClose(uint16_t Code, std::string_view Reason)
return;
}
- if (!m_CloseSent)
+ if (!m_CloseSent.exchange(true))
{
- m_CloseSent = true;
std::vector<uint8_t> CloseFrame = WsFrameCodec::BuildCloseFrame(Code, Reason);
EnqueueWrite(std::move(CloseFrame));
}
diff --git a/src/zenhttp/servers/wsasio.h b/src/zenhttp/servers/wsasio.h
index a638ea836..d8ffdc00a 100644
--- a/src/zenhttp/servers/wsasio.h
+++ b/src/zenhttp/servers/wsasio.h
@@ -65,7 +65,7 @@ private:
bool m_IsWriting = false;
std::atomic<bool> m_IsOpen{true};
- bool m_CloseSent = false;
+ std::atomic<bool> m_CloseSent{false};
};
} // namespace zen::asio_http
diff --git a/src/zenhttp/servers/wsframecodec.cpp b/src/zenhttp/servers/wsframecodec.cpp
index a4c5e0f16..e452141fe 100644
--- a/src/zenhttp/servers/wsframecodec.cpp
+++ b/src/zenhttp/servers/wsframecodec.cpp
@@ -51,6 +51,13 @@ WsFrameCodec::TryParseFrame(const uint8_t* Data, size_t Size)
HeaderSize = 10;
}
+ // Reject frames with unreasonable payload sizes to prevent OOM
+ static constexpr uint64_t kMaxPayloadSize = 256 * 1024 * 1024; // 256 MB
+ if (PayloadLen > kMaxPayloadSize)
+ {
+ return {};
+ }
+
const size_t MaskSize = Masked ? 4 : 0;
const size_t TotalFrame = HeaderSize + MaskSize + PayloadLen;
diff --git a/src/zenhttp/servers/wshttpsys.cpp b/src/zenhttp/servers/wshttpsys.cpp
index 3f0f0b447..3408b64b3 100644
--- a/src/zenhttp/servers/wshttpsys.cpp
+++ b/src/zenhttp/servers/wshttpsys.cpp
@@ -217,9 +217,8 @@ WsHttpSysConnection::ProcessReceivedData()
bool ShouldSendClose = false;
{
RwLock::ExclusiveLockScope _(m_WriteLock);
- if (!m_CloseSent)
+ if (!m_CloseSent.exchange(true))
{
- m_CloseSent = true;
ShouldSendClose = true;
}
}
@@ -412,9 +411,8 @@ WsHttpSysConnection::DoClose(uint16_t Code, std::string_view Reason)
bool ShouldSendClose = false;
{
RwLock::ExclusiveLockScope _(m_WriteLock);
- if (!m_CloseSent)
+ if (!m_CloseSent.exchange(true))
{
- m_CloseSent = true;
ShouldSendClose = true;
}
}
diff --git a/src/zenhttp/servers/wshttpsys.h b/src/zenhttp/servers/wshttpsys.h
index ab0ca381a..d854289e0 100644
--- a/src/zenhttp/servers/wshttpsys.h
+++ b/src/zenhttp/servers/wshttpsys.h
@@ -96,7 +96,7 @@ private:
Ref<WsHttpSysConnection> m_SelfRef;
std::atomic<bool> m_ShutdownRequested{false};
std::atomic<bool> m_IsOpen{true};
- bool m_CloseSent = false;
+ std::atomic<bool> m_CloseSent{false};
};
} // namespace zen