Browse Source

Fix multipart Content-Type headers with both boundary and charset parameters (#1516)

* Fix multipart Content-Type headers with both boundary and charset parameters

* Improve code readability

* Add missing forward declaration

---------

Co-authored-by: Mathieu Gaillard <[email protected]>
Mathieu Gaillard 2 years ago
parent
commit
df74526f91
2 changed files with 40 additions and 2 deletions
  1. 7 2
      httplib.h
  2. 33 0
      test/test.cc

+ 7 - 2
httplib.h

@@ -1823,6 +1823,8 @@ std::string params_to_query_str(const Params &params);
 
 void parse_query_text(const std::string &s, Params &params);
 
+bool parse_multipart_boundary(const std::string &content_type, std::string &boundary);
+
 bool parse_range_header(const std::string &s, Ranges &ranges);
 
 int close_socket(socket_t sock);
@@ -3888,9 +3890,12 @@ inline void parse_query_text(const std::string &s, Params &params) {
 
 inline bool parse_multipart_boundary(const std::string &content_type,
                                      std::string &boundary) {
-  auto pos = content_type.find("boundary=");
+  auto boundary_keyword = "boundary=";
+  auto pos = content_type.find(boundary_keyword);
   if (pos == std::string::npos) { return false; }
-  boundary = content_type.substr(pos + 9);
+  auto end = content_type.find(';', pos);
+  auto beg = pos + strlen(boundary_keyword);
+  boundary = content_type.substr(beg, end - beg);
   if (boundary.length() >= 2 && boundary.front() == '"' &&
       boundary.back() == '"') {
     boundary = boundary.substr(1, boundary.size() - 2);

+ 33 - 0
test/test.cc

@@ -169,6 +169,39 @@ TEST(ParamsToQueryTest, ConvertParamsToQuery) {
   EXPECT_EQ(detail::params_to_query_str(dic), "key1=val1&key2=val2&key3=val3");
 }
 
+TEST(ParseMultipartBoundaryTest, DefaultValue) {
+  string content_type = "multipart/form-data; boundary=something";
+  string boundary;
+  auto ret = detail::parse_multipart_boundary(content_type, boundary);
+  EXPECT_TRUE(ret);
+  EXPECT_EQ(boundary, "something");
+}
+
+TEST(ParseMultipartBoundaryTest, ValueWithQuote) {
+  string content_type = "multipart/form-data; boundary=\"gc0pJq0M:08jU534c0p\"";
+  string boundary;
+  auto ret = detail::parse_multipart_boundary(content_type, boundary);
+  EXPECT_TRUE(ret);
+  EXPECT_EQ(boundary, "gc0pJq0M:08jU534c0p");
+}
+
+TEST(ParseMultipartBoundaryTest, ValueWithCharset) {
+  string content_type = "multipart/mixed; boundary=THIS_STRING_SEPARATES;charset=UTF-8";
+  string boundary;
+  auto ret = detail::parse_multipart_boundary(content_type, boundary);
+  EXPECT_TRUE(ret);
+  EXPECT_EQ(boundary, "THIS_STRING_SEPARATES");
+}
+
+TEST(ParseMultipartBoundaryTest, ValueWithQuotesAndCharset) {
+  string content_type =
+      "multipart/mixed; boundary=\"cpp-httplib-multipart-data\"; charset=UTF-8";
+  string boundary;
+  auto ret = detail::parse_multipart_boundary(content_type, boundary);
+  EXPECT_TRUE(ret);
+  EXPECT_EQ(boundary, "cpp-httplib-multipart-data");
+}
+
 TEST(GetHeaderValueTest, DefaultValue) {
   Headers headers = {{"Dummy", "Dummy"}};
   auto val = detail::get_header_value(headers, "Content-Type", 0, "text/plain");