You've already forked cpp-httplib
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:
@ -5028,10 +5028,9 @@ public:
|
|||||||
while (buf_size() > 0) {
|
while (buf_size() > 0) {
|
||||||
switch (state_) {
|
switch (state_) {
|
||||||
case 0: { // Initial boundary
|
case 0: { // Initial boundary
|
||||||
buf_erase(buf_find(dash_boundary_crlf_));
|
auto pos = buf_find(dash_boundary_crlf_);
|
||||||
if (dash_boundary_crlf_.size() > buf_size()) { return true; }
|
if (pos == buf_size()) { return true; }
|
||||||
if (!buf_start_with(dash_boundary_crlf_)) { return false; }
|
buf_erase(pos + dash_boundary_crlf_.size());
|
||||||
buf_erase(dash_boundary_crlf_.size());
|
|
||||||
state_ = 1;
|
state_ = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
54
test/test.cc
54
test/test.cc
@ -8257,6 +8257,60 @@ TEST(MultipartFormDataTest, AccessPartHeaders) {
|
|||||||
}
|
}
|
||||||
#endif
|
#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) {
|
TEST(TaskQueueTest, IncreaseAtomicInteger) {
|
||||||
static constexpr unsigned int number_of_tasks{1000000};
|
static constexpr unsigned int number_of_tasks{1000000};
|
||||||
std::atomic_uint count{0};
|
std::atomic_uint count{0};
|
||||||
|
Reference in New Issue
Block a user