diff --git a/scripts/sync_vendor.py b/scripts/sync_vendor.py index d2a8a50b5de..467a0660870 100755 --- a/scripts/sync_vendor.py +++ b/scripts/sync_vendor.py @@ -5,7 +5,7 @@ import sys import subprocess -HTTPLIB_VERSION = "refs/tags/v0.43.2" +HTTPLIB_VERSION = "refs/tags/v0.43.3" vendor = { "https://github.com/nlohmann/json/releases/latest/download/json.hpp": "vendor/nlohmann/json.hpp", diff --git a/vendor/cpp-httplib/httplib.cpp b/vendor/cpp-httplib/httplib.cpp index 66c0b6ebd16..cb8ea9742b6 100644 --- a/vendor/cpp-httplib/httplib.cpp +++ b/vendor/cpp-httplib/httplib.cpp @@ -2506,6 +2506,10 @@ void get_remote_ip_and_port(socket_t sock, std::string &ip, int &port) { } } +// Recursive form retained so operator""_t below can compute hashes for +// switch-case labels at compile time (C++11 constexpr forbids loops). Do not +// call from runtime paths with arbitrary-length inputs — use str2tag() +// instead, which is iterative and stack-safe. constexpr unsigned int str2tag_core(const char *s, size_t l, unsigned int h) { return (l == 0) @@ -2519,7 +2523,16 @@ constexpr unsigned int str2tag_core(const char *s, size_t l, } unsigned int str2tag(const std::string &s) { - return str2tag_core(s.data(), s.size(), 0); + // Iterative form of str2tag_core: the recursive constexpr version is kept + // for compile-time UDL evaluation of short string literals, but at runtime + // we may receive arbitrarily long inputs (e.g. fuzzed Content-Type) that + // would blow the stack with one frame per character. + unsigned int h = 0; + for (auto c : s) { + h = (((std::numeric_limits::max)() >> 6) & h * 33) ^ + static_cast(c); + } + return h; } namespace udl { @@ -9777,7 +9790,15 @@ bool ClientImpl::process_request(Stream &strm, Request &req, output_error_log(error, &req); return false; } - res.body.reserve(static_cast(len)); + // Cap the reservation by payload_max_length_ to avoid OOM when a + // hostile or malformed server sends an enormous Content-Length. + // The actual body read below is bounded by payload_max_length_, + // so reserving more than that is never useful. + auto reserve_len = static_cast(len); + if (payload_max_length_ > 0 && reserve_len > payload_max_length_) { + reserve_len = payload_max_length_; + } + res.body.reserve(reserve_len); } } diff --git a/vendor/cpp-httplib/httplib.h b/vendor/cpp-httplib/httplib.h index 7e530961b9c..8d3c4c2c5b2 100644 --- a/vendor/cpp-httplib/httplib.h +++ b/vendor/cpp-httplib/httplib.h @@ -8,8 +8,8 @@ #ifndef CPPHTTPLIB_HTTPLIB_H #define CPPHTTPLIB_HTTPLIB_H -#define CPPHTTPLIB_VERSION "0.43.2" -#define CPPHTTPLIB_VERSION_NUM "0x002b02" +#define CPPHTTPLIB_VERSION "0.43.3" +#define CPPHTTPLIB_VERSION_NUM "0x002b03" #ifdef _WIN32 #if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0A00