mirror of
https://github.com/yhirose/cpp-httplib.git
synced 2026-10-19 11:19:36 +00:00
Limit the number of header lines per multipart form-data part
The multipart/form-data parser bounded the length of each individual header line via CPPHTTPLIB_HEADER_MAX_LENGTH but did not cap how many header lines a single part could contain. Within the overall payload limit, a client could pack a large number of small header lines into one part, each of which is parsed twice, inflating CPU usage. Add a per-part header-line counter that resets when a new entry begins and abort parsing once it reaches CPPHTTPLIB_HEADER_MAX_COUNT, mirroring the limit already enforced by read_headers() for request headers.
This commit is contained in:
1 parent
0c1cc8c986
commit
877a52f6b3
2 files changed
+46
No files matched your search
@@ -8095,6 +8095,13 @@ public:
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check header count limit
|
||||||
|
if (header_count_ >= CPPHTTPLIB_HEADER_MAX_COUNT) {
|
||||||
|
is_valid_ = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
header_count_++;
|
||||||
|
|
||||||
const auto header = buf_head(pos);
|
const auto header = buf_head(pos);
|
||||||
|
|
||||||
if (!parse_header(header.data(), header.data() + header.size(),
|
if (!parse_header(header.data(), header.data() + header.size(),
|
||||||
@@ -8210,6 +8217,7 @@ private:
|
|||||||
file_.filename.clear();
|
file_.filename.clear();
|
||||||
file_.content_type.clear();
|
file_.content_type.clear();
|
||||||
file_.headers.clear();
|
file_.headers.clear();
|
||||||
|
header_count_ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool start_with_case_ignore(const std::string &a, const char *b,
|
bool start_with_case_ignore(const std::string &a, const char *b,
|
||||||
@@ -8263,6 +8271,7 @@ private:
|
|||||||
size_t state_ = 0;
|
size_t state_ = 0;
|
||||||
bool is_valid_ = false;
|
bool is_valid_ = false;
|
||||||
FormData file_;
|
FormData file_;
|
||||||
|
size_t header_count_ = 0;
|
||||||
|
|
||||||
// Buffer
|
// Buffer
|
||||||
bool start_with(const std::string &a, size_t spos, size_t epos,
|
bool start_with(const std::string &a, size_t spos, size_t epos,
|
||||||
|
|||||||
@@ -13612,6 +13612,43 @@ TEST(MultipartFormDataTest, MakeFileProvider) {
|
|||||||
EXPECT_EQ(StatusCode::OK_200, res->status);
|
EXPECT_EQ(StatusCode::OK_200, res->status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(MultipartFormDataTest, ExcessivePartHeaders) {
|
||||||
|
// Verify that a multipart part with more than CPPHTTPLIB_HEADER_MAX_COUNT
|
||||||
|
// (100) headers is rejected with a 400 Bad Request response.
|
||||||
|
Server svr;
|
||||||
|
svr.Post("/post", [&](const Request & /*req*/, Response &res) {
|
||||||
|
res.set_content("ok", "text/plain");
|
||||||
|
});
|
||||||
|
|
||||||
|
thread t = thread([&] { svr.listen(HOST, PORT); });
|
||||||
|
auto se = detail::scope_exit([&] {
|
||||||
|
svr.stop();
|
||||||
|
t.join();
|
||||||
|
ASSERT_FALSE(svr.is_running());
|
||||||
|
});
|
||||||
|
|
||||||
|
svr.wait_until_ready();
|
||||||
|
|
||||||
|
// Build a multipart part with 101 custom headers (exceeding CPPHTTPLIB_HEADER_MAX_COUNT=100)
|
||||||
|
std::stringstream body;
|
||||||
|
body << "--simpleboundary\r\n"
|
||||||
|
<< "Content-Disposition: form-data; name=\"field1\"\r\n";
|
||||||
|
for (int i = 0; i < 101; i++) {
|
||||||
|
body << "X-Custom-Header-" << i << ": value\r\n";
|
||||||
|
}
|
||||||
|
body << "\r\n"
|
||||||
|
<< "value1\r\n"
|
||||||
|
<< "--simpleboundary--\r\n";
|
||||||
|
|
||||||
|
std::string content_type = "multipart/form-data; boundary=simpleboundary";
|
||||||
|
|
||||||
|
Client cli(HOST, PORT);
|
||||||
|
auto res = cli.Post("/post", body.str(), content_type.c_str());
|
||||||
|
|
||||||
|
ASSERT_TRUE(res);
|
||||||
|
EXPECT_EQ(StatusCode::BadRequest_400, res->status);
|
||||||
|
}
|
||||||
|
|
||||||
TEST(MakeFileBodyTest, Basic) {
|
TEST(MakeFileBodyTest, Basic) {
|
||||||
const std::string file_content(4096, 'Z');
|
const std::string file_content(4096, 'Z');
|
||||||
const std::string tmp_path = "./httplib_test_make_file_body.bin";
|
const std::string tmp_path = "./httplib_test_make_file_body.bin";
|
||||||
|
|||||||
Reference in new issue
Block a user