Skip to content

Commit 7b75210

Browse files
authored
Merge commit from fork
* fix(parser): Limit line length in getline Prevents potential infinite loop and memory exhaustion in stream_line_reader::getline by enforcing max line length. Signed-off-by: Ville Vesilehto <ville@vesilehto.fi> * fix: increase default max line length to 32k LONG_QUERY_VALUE test is set at 25k. Signed-off-by: Ville Vesilehto <ville@vesilehto.fi> * test(client): expect read error with too long query Adds a test case (`TooLongQueryValue`) to verify client behavior when the request URI is excessively long, exceeding `CPPHTTPLIB_MAX_LINE_LENGTH`. In this scenario, the server is expected to reset the connection. Signed-off-by: Ville Vesilehto <ville@vesilehto.fi> --------- Signed-off-by: Ville Vesilehto <ville@vesilehto.fi>
1 parent 9589519 commit 7b75210

File tree

2 files changed

+24
-0
lines changed

2 files changed

+24
-0
lines changed

httplib.h

+9
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,10 @@
145145
#define CPPHTTPLIB_LISTEN_BACKLOG 5
146146
#endif
147147

148+
#ifndef CPPHTTPLIB_MAX_LINE_LENGTH
149+
#define CPPHTTPLIB_MAX_LINE_LENGTH 32768
150+
#endif
151+
148152
/*
149153
* Headers
150154
*/
@@ -3067,6 +3071,11 @@ inline bool stream_line_reader::getline() {
30673071
#endif
30683072

30693073
for (size_t i = 0;; i++) {
3074+
if (size() >= CPPHTTPLIB_MAX_LINE_LENGTH) {
3075+
// Treat exceptionally long lines as an error to
3076+
// prevent infinite loops/memory exhaustion
3077+
return false;
3078+
}
30703079
char byte;
30713080
auto n = strm_.read(&byte, 1);
30723081

test/test.cc

+15
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ const int PORT = 1234;
4343
const string LONG_QUERY_VALUE = string(25000, '@');
4444
const string LONG_QUERY_URL = "/long-query-value?key=" + LONG_QUERY_VALUE;
4545

46+
const string TOO_LONG_QUERY_VALUE = string(35000, '@');
47+
const string TOO_LONG_QUERY_URL = "/too-long-query-value?key=" + TOO_LONG_QUERY_VALUE;
48+
4649
const std::string JSON_DATA = "{\"hello\":\"world\"}";
4750

4851
const string LARGE_DATA = string(1024 * 1024 * 100, '@'); // 100MB
@@ -2867,6 +2870,11 @@ class ServerTest : public ::testing::Test {
28672870
EXPECT_EQ(LONG_QUERY_URL, req.target);
28682871
EXPECT_EQ(LONG_QUERY_VALUE, req.get_param_value("key"));
28692872
})
2873+
.Get("/too-long-query-value",
2874+
[&](const Request &req, Response & /*res*/) {
2875+
EXPECT_EQ(TOO_LONG_QUERY_URL, req.target);
2876+
EXPECT_EQ(TOO_LONG_QUERY_VALUE, req.get_param_value("key"));
2877+
})
28702878
.Get("/array-param",
28712879
[&](const Request &req, Response & /*res*/) {
28722880
EXPECT_EQ(3u, req.get_param_value_count("array"));
@@ -3655,6 +3663,13 @@ TEST_F(ServerTest, LongQueryValue) {
36553663
EXPECT_EQ(StatusCode::UriTooLong_414, res->status);
36563664
}
36573665

3666+
TEST_F(ServerTest, TooLongQueryValue) {
3667+
auto res = cli_.Get(TOO_LONG_QUERY_URL.c_str());
3668+
3669+
ASSERT_FALSE(res);
3670+
EXPECT_EQ(Error::Read, res.error());
3671+
}
3672+
36583673
TEST_F(ServerTest, TooLongHeader) {
36593674
Request req;
36603675
req.method = "GET";

0 commit comments

Comments
 (0)