mirror of
https://github.com/yhirose/cpp-httplib.git
synced 2025-05-10 01:33:53 +00:00
Fix exception that occurs with libc++ regex engine (#368)
The regex that parses header lines potentially causes an unlimited amount of backtracking, which can cause an exception in the libc++ regex engine. The exception that occurs looks like this and is identical to the message of the exception fixed in https://github.com/yhirose/cpp-httplib/pull/280: libc++abi.dylib: terminating with uncaught exception of type std::__1::regex_error: The complexity of an attempted match against a regular expression exceeded a pre-set level. This commit eliminates the problematic backtracking.
This commit is contained in:
parent
3da925d6fe
commit
bf7700d192
@ -1764,7 +1764,7 @@ inline bool read_headers(Stream &strm, Headers &headers) {
|
|||||||
// the left or right side of the header value:
|
// the left or right side of the header value:
|
||||||
// - https://stackoverflow.com/questions/50179659/
|
// - https://stackoverflow.com/questions/50179659/
|
||||||
// - https://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html
|
// - https://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html
|
||||||
static const std::regex re(R"((.+?):[\t ]*(.+))");
|
static const std::regex re(R"(([^:]+):[\t ]*(.+))");
|
||||||
|
|
||||||
std::cmatch m;
|
std::cmatch m;
|
||||||
if (std::regex_match(line_reader.ptr(), end, m, re)) {
|
if (std::regex_match(line_reader.ptr(), end, m, re)) {
|
||||||
|
58
test/test.cc
58
test/test.cc
@ -2049,7 +2049,8 @@ TEST(ServerRequestParsingTest, TrimWhitespaceFromHeaderValues) {
|
|||||||
EXPECT_EQ(header_value, "\v bar \e");
|
EXPECT_EQ(header_value, "\v bar \e");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(ServerRequestParsingTest, ReadHeadersRegexComplexity) {
|
// Sends a raw request and verifies that there isn't a crash or exception.
|
||||||
|
static void test_raw_request(const std::string& req) {
|
||||||
Server svr;
|
Server svr;
|
||||||
svr.Get("/hi", [&](const Request & /*req*/, Response &res) {
|
svr.Get("/hi", [&](const Request & /*req*/, Response &res) {
|
||||||
res.set_content("ok", "text/plain");
|
res.set_content("ok", "text/plain");
|
||||||
@ -2066,19 +2067,60 @@ TEST(ServerRequestParsingTest, ReadHeadersRegexComplexity) {
|
|||||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
// A certain header line causes an exception if the header property is parsed
|
|
||||||
// naively with a single regex. This occurs with libc++ but not libstdc++.
|
|
||||||
const std::string req =
|
|
||||||
"GET /hi HTTP/1.1\r\n"
|
|
||||||
" : "
|
|
||||||
" ";
|
|
||||||
|
|
||||||
ASSERT_TRUE(send_request(client_read_timeout_sec, req));
|
ASSERT_TRUE(send_request(client_read_timeout_sec, req));
|
||||||
svr.stop();
|
svr.stop();
|
||||||
t.join();
|
t.join();
|
||||||
EXPECT_TRUE(listen_thread_ok);
|
EXPECT_TRUE(listen_thread_ok);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(ServerRequestParsingTest, ReadHeadersRegexComplexity) {
|
||||||
|
// A certain header line causes an exception if the header property is parsed
|
||||||
|
// naively with a single regex. This occurs with libc++ but not libstdc++.
|
||||||
|
test_raw_request(
|
||||||
|
"GET /hi HTTP/1.1\r\n"
|
||||||
|
" : "
|
||||||
|
" "
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ServerRequestParsingTest, ReadHeadersRegexComplexity2) {
|
||||||
|
// A certain header line causes an exception if the header property *name* is
|
||||||
|
// parsed with a regular expression starting with "(.+?):" - this is a non-
|
||||||
|
// greedy matcher and requires backtracking when there are a lot of ":"
|
||||||
|
// characters.
|
||||||
|
// This occurs with libc++ but not libstdc++.
|
||||||
|
test_raw_request(
|
||||||
|
"GET /hi HTTP/1.1\r\n"
|
||||||
|
":-:::::::::::::::::::::::::::-::::::::::::::::::::::::@-&&&&&&&&&&&"
|
||||||
|
"--:::::::-:::::::::::::::::::::::::::::-:::::::::::::::::@-&&&&&&&&"
|
||||||
|
"&&&--:::::::-:::::::::::::::::::::::::::::-:::::::::::::::::@-:::::"
|
||||||
|
"::-:::::::::::::::::@-&&&&&&&&&&&--:::::::-::::::::::::::::::::::::"
|
||||||
|
":::::-:::::::::::::::::@-&&&&&&&&&&&--:::::::-:::::::::::::::::::::"
|
||||||
|
"::::::::-:::::::::::::::::@-&&&&&&&--:::::::-::::::::::::::::::::::"
|
||||||
|
":::::::-:::::::::::::::::@-&&&&&&&&&&&--:::::::-:::::::::::::::::::"
|
||||||
|
"::::::::::-:::::::::::::::::@-&&&&&::::::::::::-:::::::::::::::::@-"
|
||||||
|
"&&&&&&&&&&&--:::::::-:::::::::::::::::::::::::::::-::::::::::::::::"
|
||||||
|
":@-&&&&&&&&&&&--:::::::-:::::::::::::::::::::::::::::-:::::::::::::"
|
||||||
|
"::::@-&&&&&&&&&&&--:::::::-:::::::::::::::::::::::::::::-::::::@-&&"
|
||||||
|
"&&&&&&&&&--:::::::-:::::::::::::::::::::::::::::-:::::::::::::::::@"
|
||||||
|
"::::::-:::::::::::::::::::::::::::::-:::::::::::::::::@-&&&&&&&&&&&"
|
||||||
|
"--:::::::-:::::::::::::::::::::::::::::-:::::::::::::::::@-&&&&&&&&"
|
||||||
|
"&&&--:::::::-:::::::::::::::::::::::::::::-:::::::::::::::::@-&&&&&"
|
||||||
|
"&&&&&&--:::::::-:::::::::::::::::::::::::::::-:::::::::::::::::@-&&"
|
||||||
|
"&&&&&&&&&--:::::::-:::::::::::::::::::::::::::::-:::::::::::::::::@"
|
||||||
|
"-&&&&&&&&&&&--:::::::-:::::::::::::::::::::::::::::-:::::::::::::::"
|
||||||
|
"::@-&&&&&&&&&&&--:::::::-:::::::::::::::::::::::::::::-::::::::::::"
|
||||||
|
":::::@-&&&&&&&&&&&::-:::::::::::::::::@-&&&&&&&&&&&--:::::::-::::::"
|
||||||
|
":::::::::::::::::::::::-:::::::::::::::::@-&&&&&&&&&&&--:::::::-:::"
|
||||||
|
"::::::::::::::::::::::::::-:::::::::::::::::@-&&&&&&&&&&&--:::::::-"
|
||||||
|
":::::::::::::::::::::::::::::-:::::::::::::::::@-&&&&&&&&&&&---&&:&"
|
||||||
|
"&&.0------------:-:::::::::::::::::::::::::::::-:::::::::::::::::@-"
|
||||||
|
"&&&&&&&&&&&--:::::::-:::::::::::::::::::::::::::::-::::::::::::::::"
|
||||||
|
":@-&&&&&&&&&&&--:::::::-:::::::::::::::::::::::::::::-:::::::::::::"
|
||||||
|
"::::@-&&&&&&&&&&&---&&:&&&.0------------O--------\rH PUTHTTP/1.1\r\n"
|
||||||
|
"&&&%%%");
|
||||||
|
}
|
||||||
|
|
||||||
TEST(ServerStopTest, StopServerWithChunkedTransmission) {
|
TEST(ServerStopTest, StopServerWithChunkedTransmission) {
|
||||||
Server svr;
|
Server svr;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user