From e9575bcb783d9b731c133be47c50b03130d9ef8d Mon Sep 17 00:00:00 2001
From: tmahring <tmahring@tmweb.at>
Date: Fri, 11 Sep 2020 02:27:01 +0200
Subject: [PATCH] don't replace plus with space in headers (#649)

* don't replace plus with space in headers

* fixed forward handling with changed header parsing

* add test for boundaries containing plus chars
---
 httplib.h    |  4 ++--
 test/test.cc | 35 +++++++++++++++++++++++++++++++++++
 2 files changed, 37 insertions(+), 2 deletions(-)

diff --git a/httplib.h b/httplib.h
index dc5fefd..8bf8604 100644
--- a/httplib.h
+++ b/httplib.h
@@ -2464,7 +2464,7 @@ inline bool parse_header(const char *beg, const char *end, T fn) {
   }
 
   if (p < end) {
-    fn(std::string(beg, key_end), decode_url(std::string(p, end), true));
+    fn(std::string(beg, key_end), decode_url(std::string(p, end), false));
     return true;
   }
 
@@ -4768,7 +4768,7 @@ inline bool ClientImpl::redirect(const Request &req, Response &res) {
     return false;
   }
 
-  auto location = res.get_header_value("location");
+  auto location = detail::decode_url(res.get_header_value("location"), true);
   if (location.empty()) { return false; }
 
   const static std::regex re(
diff --git a/test/test.cc b/test/test.cc
index 46cea48..910d2c3 100644
--- a/test/test.cc
+++ b/test/test.cc
@@ -2323,6 +2323,41 @@ TEST_F(ServerTest, PostMulitpartFilsContentReceiver) {
   EXPECT_EQ(200, res->status);
 }
 
+TEST_F(ServerTest, PostMulitpartPlusBoundary) {
+  MultipartFormDataItems items = {
+      {"text1", "text default", "", ""},
+      {"text2", "aωb", "", ""},
+      {"file1", "h\ne\n\nl\nl\no\n", "hello.txt", "text/plain"},
+      {"file2", "{\n  \"world\", true\n}\n", "world.json", "application/json"},
+      {"file3", "", "", "application/octet-stream"},
+  };
+
+  auto boundary = std::string("+++++");
+
+  std::string body;
+
+  for (const auto &item : items) {
+    body += "--" + boundary + "\r\n";
+    body += "Content-Disposition: form-data; name=\"" + item.name + "\"";
+    if (!item.filename.empty()) {
+      body += "; filename=\"" + item.filename + "\"";
+    }
+    body += "\r\n";
+    if (!item.content_type.empty()) {
+      body += "Content-Type: " + item.content_type + "\r\n";
+    }
+    body += "\r\n";
+    body += item.content + "\r\n";
+  }
+  body += "--" + boundary + "--\r\n";
+
+  std::string content_type = "multipart/form-data; boundary=" + boundary;
+  auto res = cli_.Post("/content_receiver", body, content_type.c_str());
+
+  ASSERT_TRUE(res);
+  EXPECT_EQ(200, res->status);
+}
+
 TEST_F(ServerTest, PostContentReceiverGzip) {
   cli_.set_compress(true);
   auto res = cli_.Post("/content_receiver", "content", "text/plain");