1
0
mirror of synced 2025-07-02 20:02:24 +03:00

Fix bad request for multipart form data with boundary split (#2159)

* Add test for multipart form data with boundary split

Add a test for multipart form data requests with a large header which
leads to a split inside the boundary because of the read buffer size
inside the SocketStream class.

* Fix bad request for multipart form data with boundary split

Fix a bad request (400) response for multipart form data requests with
a large header which leads to a split inside the boundary because of the
read buffer size inside the SocketStream class. The parse function
inside the MultipartFormDataParser wrongly erase the receive buffer if
it doesn't find the boundary inside the buffer during first call.
This commit is contained in:
herbrechtsmeier
2025-06-24 18:57:32 +02:00
committed by GitHub
parent b6c55c6030
commit de5a255ac6
2 changed files with 57 additions and 4 deletions

View File

@ -5028,10 +5028,9 @@ public:
while (buf_size() > 0) {
switch (state_) {
case 0: { // Initial boundary
buf_erase(buf_find(dash_boundary_crlf_));
if (dash_boundary_crlf_.size() > buf_size()) { return true; }
if (!buf_start_with(dash_boundary_crlf_)) { return false; }
buf_erase(dash_boundary_crlf_.size());
auto pos = buf_find(dash_boundary_crlf_);
if (pos == buf_size()) { return true; }
buf_erase(pos + dash_boundary_crlf_.size());
state_ = 1;
break;
}

View File

@ -8257,6 +8257,60 @@ TEST(MultipartFormDataTest, AccessPartHeaders) {
}
#endif
TEST(MultipartFormDataTest, LargeHeader) {
auto handled = false;
Server svr;
svr.Post("/test", [&](const Request &req, Response &) {
ASSERT_EQ(1u, req.files.size());
auto it = req.files.begin();
ASSERT_EQ("name1", it->second.name);
ASSERT_EQ("text1", it->second.content);
handled = true;
});
thread t = thread([&] { svr.listen(HOST, PORT); });
auto se = detail::scope_exit([&] {
svr.stop();
t.join();
ASSERT_FALSE(svr.is_running());
ASSERT_TRUE(handled);
});
svr.wait_until_ready();
auto boundary = std::string("cpp-httplib-multipart-data");
std::string content = "--" + boundary +
"\r\n"
"Content-Disposition: form-data; name=\"name1\"\r\n"
"\r\n"
"text1\r\n"
"--" +
boundary + "--\r\n";
std::string header_prefix = "POST /test HTTP/1.1\r\n"
"Content-Type: multipart/form-data;boundary=" +
boundary +
"\r\n"
"Content-Length: " +
std::to_string(content.size()) +
"\r\n"
"Dummy-Header: ";
std::string header_suffix = "\r\n"
"\r\n";
size_t read_buff_size = 1024u * 4; // SocketStream::read_buff_size_
size_t header_dummy_size =
read_buff_size -
(header_prefix.size() + header_suffix.size() + boundary.size() / 2);
auto header_dummy = std::string(header_dummy_size, '@');
auto req = header_prefix + header_dummy + header_suffix + content;
std::string response;
ASSERT_TRUE(send_request(1, req, &response));
ASSERT_EQ("200", response.substr(9, 3));
}
TEST(TaskQueueTest, IncreaseAtomicInteger) {
static constexpr unsigned int number_of_tasks{1000000};
std::atomic_uint count{0};