yhirose пре 1 месец
родитељ
комит
8bffbe3ff2
2 измењених фајлова са 54 додато и 7 уклоњено
  1. 8 7
      httplib.h
  2. 46 0
      test/test.cc

+ 8 - 7
httplib.h

@@ -7770,13 +7770,14 @@ public:
 
               it = params.find("filename*");
               if (it != params.end()) {
-                // Only allow UTF-8 encoding...
-                thread_local const std::regex re_rfc5987_encoding(
-                    R"~(^UTF-8''(.+?)$)~", std::regex_constants::icase);
-
-                std::smatch m2;
-                if (std::regex_match(it->second, m2, re_rfc5987_encoding)) {
-                  file_.filename = decode_path_component(m2[1]); // override...
+                // RFC 5987: only UTF-8 encoding is allowed
+                const auto &val = it->second;
+                constexpr size_t prefix_len = 7; // length of "UTF-8''"
+                if (val.size() > prefix_len &&
+                    case_ignore::to_lower(val.substr(0, prefix_len)) ==
+                        "utf-8''") {
+                  file_.filename = decode_path_component(
+                      val.substr(prefix_len)); // override...
                 } else {
                   is_valid_ = false;
                   return false;

+ 46 - 0
test/test.cc

@@ -11609,6 +11609,52 @@ TEST(MultipartFormDataTest, AlternateFilename) {
   ASSERT_TRUE(send_request(1, req));
 }
 
+TEST(MultipartFormDataTest, AlternateFilenameLongValueAndCaseInsensitive) {
+  auto handled = false;
+
+  Server svr;
+  svr.Post("/test", [&](const Request &req, Response &res) {
+    // Case-insensitive "utf-8''" prefix with a long value
+    const auto &file = req.form.get_file("file1");
+    ASSERT_EQ("file1", file.name);
+    std::string expected_filename(2000, 'A');
+    ASSERT_EQ(expected_filename, file.filename);
+
+    res.set_content("ok", "text/plain");
+    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();
+
+  // Build body with a long filename* value using mixed-case prefix "Utf-8''"
+  // Prior to the fix, this would cause O(N) stack recursion in std::regex
+  std::string long_filename(2000, 'A');
+  std::string body = "----------\r\n"
+                     "Content-Disposition: form-data; name=\"file1\"; "
+                     "filename*=\"Utf-8''" +
+                     long_filename +
+                     "\"\r\n"
+                     "\r\n"
+                     "hello\r\n"
+                     "------------\r\n";
+
+  auto req = "POST /test HTTP/1.1\r\n"
+             "Content-Type: multipart/form-data;boundary=--------\r\n"
+             "Content-Length: " +
+             std::to_string(body.size()) +
+             "\r\n\r\n" + body;
+
+  ASSERT_TRUE(send_request(1, req));
+}
+
 TEST(MultipartFormDataTest, CloseDelimiterWithoutCRLF) {
   auto handled = false;