http: parse server Content-Length strictly

This commit is contained in:
alhudz
2026-06-23 17:37:41 +05:30
parent 49c9cfc315
commit 07f7c7521d
2 changed files with 24 additions and 9 deletions
@@ -30,6 +30,7 @@
#include <boost/regex.hpp> #include <boost/regex.hpp>
#include "http_protocol_handler.h" #include "http_protocol_handler.h"
#include "string_tools.h" #include "string_tools.h"
#include "string_tools_lexical.h"
#include "file_io_utils.h" #include "file_io_utils.h"
#include "net_parse_helpers.h" #include "net_parse_helpers.h"
#include "time_helper.h" #include "time_helper.h"
@@ -599,15 +600,11 @@ namespace net_utils
template<class t_connection_context> template<class t_connection_context>
bool simple_http_connection_handler<t_connection_context>::get_len_from_content_lenght(const std::string& str, size_t& OUT len) bool simple_http_connection_handler<t_connection_context>::get_len_from_content_lenght(const std::string& str, size_t& OUT len)
{ {
static const boost::regex rexp_mach_field("\\d+", boost::regex::normal); // Content-Length must be 1*DIGIT (RFC 7230 3.3.2). Parse the whole value
std::string res; // strictly, matching the client side, so a field such as "5abc" or "0x10"
boost::smatch result; // is rejected rather than silently yielding a body length from its leading
if(!(boost::regex_search( str, result, rexp_mach_field, boost::match_default) && result[0].matched)) // digits.
return false; return string_tools::get_xtype_from_string(len, str);
try { len = boost::lexical_cast<size_t>(result[0]); }
catch(...) { return false; }
return true;
} }
//----------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------
template<class t_connection_context> template<class t_connection_context>
+18
View File
@@ -875,6 +875,24 @@ TEST(HTTP, Server_Parses_First_Header_After_Split_Request_Line)
EXPECT_EQ(body, capture.requests.front().m_body); 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) TEST(HTTP, Server_Rejects_Malformed_First_Header)
{ {
const auto capture = feed_http_request( const auto capture = feed_http_request(