You've already forked cpp-httplib
Feature/multipart headers (#2152)
* Adds headers to multipart form data Adds a `headers` field to the `MultipartFormData` struct. Populates this field by parsing headers from the multipart form data. This allows access to specific headers associated with each form data part. * Adds multipart header access test Verifies the correct retrieval of headers from multipart form data file parts. Ensures that custom and content-related headers are accessible and parsed as expected. * Enables automatic test discovery with GoogleTest Uses `gtest_discover_tests` to automatically find and run tests, simplifying test maintenance and improving discoverability. * Removes explicit GoogleTest include * Refactors header parsing logic Improves header parsing by using a dedicated parsing function, resulting in cleaner and more robust code. This change also adds error handling during header parsing, returning an error and marking the request as invalid if parsing fails. * clang-format corrected * Renames variable for better readability. Renames the `customHeader` variable to `custom_header` for improved code readability and consistency. * typo
This commit is contained in:
12
httplib.h
12
httplib.h
@ -544,6 +544,7 @@ struct MultipartFormData {
|
||||
std::string content;
|
||||
std::string filename;
|
||||
std::string content_type;
|
||||
Headers headers;
|
||||
};
|
||||
using MultipartFormDataItems = std::vector<MultipartFormData>;
|
||||
using MultipartFormDataMap = std::multimap<std::string, MultipartFormData>;
|
||||
@ -5045,6 +5046,16 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
// parse and emplace space trimmed headers into a map
|
||||
if (!parse_header(
|
||||
header.data(), header.data() + header.size(),
|
||||
[&](const std::string &key, const std::string &val) {
|
||||
file_.headers.emplace(key, val);
|
||||
})) {
|
||||
is_valid_ = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
constexpr const char header_content_type[] = "Content-Type:";
|
||||
|
||||
if (start_with_case_ignore(header, header_content_type)) {
|
||||
@ -5144,6 +5155,7 @@ private:
|
||||
file_.name.clear();
|
||||
file_.filename.clear();
|
||||
file_.content_type.clear();
|
||||
file_.headers.clear();
|
||||
}
|
||||
|
||||
bool start_with_case_ignore(const std::string &a, const char *b) const {
|
||||
|
62
test/test.cc
62
test/test.cc
@ -8010,6 +8010,68 @@ TEST(MultipartFormDataTest, ContentLength) {
|
||||
ASSERT_TRUE(send_request(1, req, &response));
|
||||
ASSERT_EQ("200", response.substr(9, 3));
|
||||
}
|
||||
|
||||
TEST(MultipartFormDataTest, AccessPartHeaders) {
|
||||
auto handled = false;
|
||||
|
||||
Server svr;
|
||||
svr.Post("/test", [&](const Request &req, Response &) {
|
||||
ASSERT_EQ(2u, req.files.size());
|
||||
|
||||
auto it = req.files.begin();
|
||||
ASSERT_EQ("text1", it->second.name);
|
||||
ASSERT_EQ("text1", it->second.content);
|
||||
ASSERT_EQ(1, it->second.headers.count("Content-Length"));
|
||||
auto content_length = it->second.headers.find("CONTENT-length");
|
||||
ASSERT_EQ("5", content_length->second);
|
||||
ASSERT_EQ(3, it->second.headers.size());
|
||||
|
||||
++it;
|
||||
ASSERT_EQ("text2", it->second.name);
|
||||
ASSERT_EQ("text2", it->second.content);
|
||||
auto &headers = it->second.headers;
|
||||
ASSERT_EQ(3, headers.size());
|
||||
auto custom_header = headers.find("x-whatever");
|
||||
ASSERT_TRUE(custom_header != headers.end());
|
||||
ASSERT_NE("customvalue", custom_header->second);
|
||||
ASSERT_EQ("CustomValue", custom_header->second);
|
||||
ASSERT_TRUE(headers.find("X-Test") == headers.end()); // text1 header
|
||||
|
||||
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 req = "POST /test HTTP/1.1\r\n"
|
||||
"Content-Type: multipart/form-data;boundary=--------\r\n"
|
||||
"Content-Length: 232\r\n"
|
||||
"\r\n----------\r\n"
|
||||
"Content-Disposition: form-data; name=\"text1\"\r\n"
|
||||
"Content-Length: 5\r\n"
|
||||
"X-Test: 1\r\n"
|
||||
"\r\n"
|
||||
"text1"
|
||||
"\r\n----------\r\n"
|
||||
"Content-Disposition: form-data; name=\"text2\"\r\n"
|
||||
"Content-Type: text/plain\r\n"
|
||||
"X-Whatever: CustomValue\r\n"
|
||||
"\r\n"
|
||||
"text2"
|
||||
"\r\n------------\r\n"
|
||||
"That should be disregarded. Not even read";
|
||||
|
||||
std::string response;
|
||||
ASSERT_TRUE(send_request(1, req, &response));
|
||||
ASSERT_EQ("200", response.substr(9, 3));
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST(TaskQueueTest, IncreaseAtomicInteger) {
|
||||
|
Reference in New Issue
Block a user