You've already forked cpp-httplib
							
							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>
This commit is contained in:
		@@ -145,6 +145,10 @@
 | 
				
			|||||||
#define CPPHTTPLIB_LISTEN_BACKLOG 5
 | 
					#define CPPHTTPLIB_LISTEN_BACKLOG 5
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef CPPHTTPLIB_MAX_LINE_LENGTH
 | 
				
			||||||
 | 
					#define CPPHTTPLIB_MAX_LINE_LENGTH 32768
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Headers
 | 
					 * Headers
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@@ -3067,6 +3071,11 @@ inline bool stream_line_reader::getline() {
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  for (size_t i = 0;; i++) {
 | 
					  for (size_t i = 0;; i++) {
 | 
				
			||||||
 | 
					    if (size() >= CPPHTTPLIB_MAX_LINE_LENGTH) {
 | 
				
			||||||
 | 
					      // Treat exceptionally long lines as an error to
 | 
				
			||||||
 | 
					      // prevent infinite loops/memory exhaustion
 | 
				
			||||||
 | 
					      return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    char byte;
 | 
					    char byte;
 | 
				
			||||||
    auto n = strm_.read(&byte, 1);
 | 
					    auto n = strm_.read(&byte, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										15
									
								
								test/test.cc
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								test/test.cc
									
									
									
									
									
								
							@@ -43,6 +43,9 @@ const int PORT = 1234;
 | 
				
			|||||||
const string LONG_QUERY_VALUE = string(25000, '@');
 | 
					const string LONG_QUERY_VALUE = string(25000, '@');
 | 
				
			||||||
const string LONG_QUERY_URL = "/long-query-value?key=" + LONG_QUERY_VALUE;
 | 
					const string LONG_QUERY_URL = "/long-query-value?key=" + LONG_QUERY_VALUE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const string TOO_LONG_QUERY_VALUE = string(35000, '@');
 | 
				
			||||||
 | 
					const string TOO_LONG_QUERY_URL = "/too-long-query-value?key=" + TOO_LONG_QUERY_VALUE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const std::string JSON_DATA = "{\"hello\":\"world\"}";
 | 
					const std::string JSON_DATA = "{\"hello\":\"world\"}";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const string LARGE_DATA = string(1024 * 1024 * 100, '@'); // 100MB
 | 
					const string LARGE_DATA = string(1024 * 1024 * 100, '@'); // 100MB
 | 
				
			||||||
@@ -2867,6 +2870,11 @@ protected:
 | 
				
			|||||||
               EXPECT_EQ(LONG_QUERY_URL, req.target);
 | 
					               EXPECT_EQ(LONG_QUERY_URL, req.target);
 | 
				
			||||||
               EXPECT_EQ(LONG_QUERY_VALUE, req.get_param_value("key"));
 | 
					               EXPECT_EQ(LONG_QUERY_VALUE, req.get_param_value("key"));
 | 
				
			||||||
             })
 | 
					             })
 | 
				
			||||||
 | 
					        .Get("/too-long-query-value",
 | 
				
			||||||
 | 
					             [&](const Request &req, Response & /*res*/) {
 | 
				
			||||||
 | 
					               EXPECT_EQ(TOO_LONG_QUERY_URL, req.target);
 | 
				
			||||||
 | 
					               EXPECT_EQ(TOO_LONG_QUERY_VALUE, req.get_param_value("key"));
 | 
				
			||||||
 | 
					             })
 | 
				
			||||||
        .Get("/array-param",
 | 
					        .Get("/array-param",
 | 
				
			||||||
             [&](const Request &req, Response & /*res*/) {
 | 
					             [&](const Request &req, Response & /*res*/) {
 | 
				
			||||||
               EXPECT_EQ(3u, req.get_param_value_count("array"));
 | 
					               EXPECT_EQ(3u, req.get_param_value_count("array"));
 | 
				
			||||||
@@ -3655,6 +3663,13 @@ TEST_F(ServerTest, LongQueryValue) {
 | 
				
			|||||||
  EXPECT_EQ(StatusCode::UriTooLong_414, res->status);
 | 
					  EXPECT_EQ(StatusCode::UriTooLong_414, res->status);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST_F(ServerTest, TooLongQueryValue) {
 | 
				
			||||||
 | 
					  auto res = cli_.Get(TOO_LONG_QUERY_URL.c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ASSERT_FALSE(res);
 | 
				
			||||||
 | 
					  EXPECT_EQ(Error::Read, res.error());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TEST_F(ServerTest, TooLongHeader) {
 | 
					TEST_F(ServerTest, TooLongHeader) {
 | 
				
			||||||
  Request req;
 | 
					  Request req;
 | 
				
			||||||
  req.method = "GET";
 | 
					  req.method = "GET";
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user