From 07f7c7521d9d0bb439e7c5bb13c2b1701b93d7b6 Mon Sep 17 00:00:00 2001 From: alhudz Date: Tue, 23 Jun 2026 17:37:41 +0530 Subject: [PATCH] http: parse server Content-Length strictly --- .../epee/include/net/http_protocol_handler.inl | 15 ++++++--------- tests/unit_tests/http.cpp | 18 ++++++++++++++++++ 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/contrib/epee/include/net/http_protocol_handler.inl b/contrib/epee/include/net/http_protocol_handler.inl index bd6e40488..4b8c1f450 100644 --- a/contrib/epee/include/net/http_protocol_handler.inl +++ b/contrib/epee/include/net/http_protocol_handler.inl @@ -30,6 +30,7 @@ #include #include "http_protocol_handler.h" #include "string_tools.h" +#include "string_tools_lexical.h" #include "file_io_utils.h" #include "net_parse_helpers.h" #include "time_helper.h" @@ -599,15 +600,11 @@ namespace net_utils template bool simple_http_connection_handler::get_len_from_content_lenght(const std::string& str, size_t& OUT len) { - static const boost::regex rexp_mach_field("\\d+", boost::regex::normal); - std::string res; - boost::smatch result; - if(!(boost::regex_search( str, result, rexp_mach_field, boost::match_default) && result[0].matched)) - return false; - - try { len = boost::lexical_cast(result[0]); } - catch(...) { return false; } - return true; + // Content-Length must be 1*DIGIT (RFC 7230 3.3.2). Parse the whole value + // strictly, matching the client side, so a field such as "5abc" or "0x10" + // is rejected rather than silently yielding a body length from its leading + // digits. + return string_tools::get_xtype_from_string(len, str); } //----------------------------------------------------------------------------------- template diff --git a/tests/unit_tests/http.cpp b/tests/unit_tests/http.cpp index 74fe41293..5ecdd84d8 100644 --- a/tests/unit_tests/http.cpp +++ b/tests/unit_tests/http.cpp @@ -875,6 +875,24 @@ TEST(HTTP, Server_Parses_First_Header_After_Split_Request_Line) EXPECT_EQ(body, capture.requests.front().m_body); } +TEST(HTTP, Server_Rejects_Malformed_Content_Length) +{ + const std::string body = "0123456789"; + for (const char* len : {"5abc", "0x10", "+10", "1 0", "abc"}) + { + const auto capture = feed_http_request( + "POST /json_rpc HTTP/1.1\r\n" + "Content-Length: " + std::string(len) + "\r\n" + "Host: example.com\r\n" + "\r\n" + body + ); + + ASSERT_EQ(1u, capture.results.size()); + EXPECT_FALSE(capture.results.front()) << "accepted Content-Length: " << len; + EXPECT_TRUE(capture.requests.empty()) << "accepted Content-Length: " << len; + } +} + TEST(HTTP, Server_Rejects_Malformed_First_Header) { const auto capture = feed_http_request(