yhirose 5 years ago
parent
commit
e1acb949e7
2 changed files with 37 additions and 24 deletions
  1. 8 9
      httplib.h
  2. 29 15
      test/test.cc

+ 8 - 9
httplib.h

@@ -1923,9 +1923,7 @@ inline ssize_t write_headers(Stream &strm, const T &info,
                              const Headers &headers) {
   ssize_t write_len = 0;
   for (const auto &x : info.headers) {
-    if (x.first == "EXCEPTION_WHAT") {
-      continue;
-    }
+    if (x.first == "EXCEPTION_WHAT") { continue; }
     auto len =
         strm.write_format("%s: %s\r\n", x.first.c_str(), x.second.c_str());
     if (len < 0) { return len; }
@@ -2042,7 +2040,8 @@ inline std::string encode_url(const std::string &s) {
   return result;
 }
 
-inline std::string decode_url(const std::string &s) {
+inline std::string decode_url(const std::string &s,
+                              bool convert_plus_to_space) {
   std::string result;
 
   for (size_t i = 0; i < s.size(); i++) {
@@ -2068,7 +2067,7 @@ inline std::string decode_url(const std::string &s) {
           result += s[i];
         }
       }
-    } else if (s[i] == '+') {
+    } else if (convert_plus_to_space && s[i] == '+') {
       result += ' ';
     } else {
       result += s[i];
@@ -2102,7 +2101,7 @@ inline void parse_query_text(const std::string &s, Params &params) {
         val.assign(b2, e2);
       }
     });
-    params.emplace(key, decode_url(val));
+    params.emplace(decode_url(key, true), decode_url(val, true));
   });
 }
 
@@ -3024,7 +3023,7 @@ inline bool Server::parse_request_line(const char *s, Request &req) {
     req.version = std::string(m[5]);
     req.method = std::string(m[1]);
     req.target = std::string(m[2]);
-    req.path = detail::decode_url(m[3]);
+    req.path = detail::decode_url(m[3], false);
 
     // Parse query text
     auto len = std::distance(m[4].first, m[4].second);
@@ -3391,9 +3390,9 @@ inline bool Server::listen_internal() {
       }
 
 #if __cplusplus > 201703L
-        task_queue->enqueue([=, this]() { process_and_close_socket(sock); });
+      task_queue->enqueue([=, this]() { process_and_close_socket(sock); });
 #else
-        task_queue->enqueue([=]() { process_and_close_socket(sock); });
+      task_queue->enqueue([=]() { process_and_close_socket(sock); });
 #endif
     }
 

+ 29 - 15
test/test.cc

@@ -78,18 +78,18 @@ TEST(ParseQueryTest, ParseQueryString) {
 }
 
 TEST(ParamsToQueryTest, ConvertParamsToQuery) {
-    Params dic;
+  Params dic;
 
-    EXPECT_EQ(detail::params_to_query_str(dic), "");
+  EXPECT_EQ(detail::params_to_query_str(dic), "");
 
-    dic.emplace("key1", "val1");
+  dic.emplace("key1", "val1");
 
-    EXPECT_EQ(detail::params_to_query_str(dic), "key1=val1");
+  EXPECT_EQ(detail::params_to_query_str(dic), "key1=val1");
 
-    dic.emplace("key2", "val2");
-    dic.emplace("key3", "val3");
+  dic.emplace("key2", "val2");
+  dic.emplace("key3", "val3");
 
-    EXPECT_EQ(detail::params_to_query_str(dic), "key1=val1&key2=val2&key3=val3");
+  EXPECT_EQ(detail::params_to_query_str(dic), "key1=val1&key2=val2&key3=val3");
 }
 
 TEST(GetHeaderValueTest, DefaultValue) {
@@ -668,7 +668,8 @@ TEST(Server, BindAndListenSeparately) {
 
 #ifdef CPPHTTPLIB_OPENSSL_SUPPORT
 TEST(SSLServer, BindAndListenSeparately) {
-  SSLServer svr(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE, CLIENT_CA_CERT_FILE, CLIENT_CA_CERT_DIR);
+  SSLServer svr(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE, CLIENT_CA_CERT_FILE,
+                CLIENT_CA_CERT_DIR);
   int port = svr.bind_to_any_port("0.0.0.0");
   ASSERT_TRUE(svr.is_valid());
   ASSERT_TRUE(port > 0);
@@ -710,6 +711,12 @@ protected:
              [&](const Request & /*req*/, Response &res) {
                res.set_content("Hello World!", "text/plain");
              })
+        .Get("/a\\+\\+b",
+             [&](const Request &req, Response &res) {
+               ASSERT_TRUE(req.has_param("a +b"));
+               auto val = req.get_param_value("a +b");
+               res.set_content(val, "text/plain");
+             })
         .Get("/", [&](const Request & /*req*/,
                       Response &res) { res.set_redirect("/hi"); })
         .Post("/person",
@@ -1459,6 +1466,13 @@ TEST_F(ServerTest, EndWithPercentCharacterInQuery) {
   EXPECT_EQ(404, res->status);
 }
 
+TEST_F(ServerTest, PlusSignEncoding) {
+  auto res = cli_.Get("/a+%2Bb?a %2bb=a %2Bb");
+  ASSERT_TRUE(res != nullptr);
+  EXPECT_EQ(200, res->status);
+  EXPECT_EQ("a +b", res->body);
+}
+
 TEST_F(ServerTest, MultipartFormData) {
   MultipartFormDataItems items = {
       {"text1", "text default", "", ""},
@@ -1727,7 +1741,8 @@ TEST_F(ServerTest, PutContentWithDeflate) {
   httplib::Headers headers;
   headers.emplace("Content-Encoding", "deflate");
   // PUT in deflate format:
-  auto res = cli_.Put("/put", headers, "\170\234\013\010\015\001\0\001\361\0\372", "text/plain");
+  auto res = cli_.Put("/put", headers,
+                      "\170\234\013\010\015\001\0\001\361\0\372", "text/plain");
 
   ASSERT_TRUE(res != nullptr);
   EXPECT_EQ(200, res->status);
@@ -2050,7 +2065,7 @@ TEST(ServerRequestParsingTest, TrimWhitespaceFromHeaderValues) {
 }
 
 // Sends a raw request and verifies that there isn't a crash or exception.
-static void test_raw_request(const std::string& req) {
+static void test_raw_request(const std::string &req) {
   Server svr;
   svr.Get("/hi", [&](const Request & /*req*/, Response &res) {
     res.set_content("ok", "text/plain");
@@ -2208,11 +2223,10 @@ TEST(MountTest, Unmount) {
 TEST(ExceptionTest, ThrowExceptionInHandler) {
   Server svr;
 
-  svr.Get("/hi",
-          [&](const Request & /*req*/, Response &res) {
-            throw std::runtime_error("exception...");
-            res.set_content("Hello World!", "text/plain");
-          });
+  svr.Get("/hi", [&](const Request & /*req*/, Response &res) {
+    throw std::runtime_error("exception...");
+    res.set_content("Hello World!", "text/plain");
+  });
 
   auto listen_thread = std::thread([&svr]() { svr.listen("localhost", PORT); });
   while (!svr.is_running()) {