From e1acb949e74c663dc9dedc04e41d8bb0dfafb7c7 Mon Sep 17 00:00:00 2001 From: yhirose Date: Fri, 13 Mar 2020 18:43:29 -0400 Subject: [PATCH] Fix #382 --- httplib.h | 17 ++++++++--------- test/test.cc | 44 +++++++++++++++++++++++++++++--------------- 2 files changed, 37 insertions(+), 24 deletions(-) diff --git a/httplib.h b/httplib.h index 947f08d..9a9c9a2 100644 --- a/httplib.h +++ b/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 ¶ms) { 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 } diff --git a/test/test.cc b/test/test.cc index 3e9e2a3..a3b2d2f 100644 --- a/test/test.cc +++ b/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()) {