From b5927aec123351dcf796e1fba8a6a1805d294cbe Mon Sep 17 00:00:00 2001 From: yhirose Date: Mon, 17 Dec 2018 21:07:38 -0500 Subject: [PATCH] fix #116 --- httplib.h | 45 ++++++++++++++++++++++++++++++++++----------- test/test.cc | 27 ++++++++++++++++++++------- 2 files changed, 54 insertions(+), 18 deletions(-) diff --git a/httplib.h b/httplib.h index 7d4c7a0..7576cee 100644 --- a/httplib.h +++ b/httplib.h @@ -132,11 +132,13 @@ struct Request { Progress progress; bool has_header(const char* key) const; - std::string get_header_value(const char* key) const; + std::string get_header_value(const char* key, size_t id = 0) const; + size_t get_header_value_count(const char* key) const; void set_header(const char* key, const char* val); bool has_param(const char* key) const; - std::string get_param_value(const char* key) const; + std::string get_param_value(const char* key, size_t id = 0) const; + size_t get_param_value_count(const char* key) const; bool has_file(const char* key) const; MultipartFile get_file_value(const char* key) const; @@ -150,7 +152,8 @@ struct Response { std::function streamcb; bool has_header(const char* key) const; - std::string get_header_value(const char* key) const; + std::string get_header_value(const char* key, size_t id = 0) const; + size_t get_header_value_count(const char* key) const; void set_header(const char* key, const char* val); void set_redirect(const char* uri); @@ -771,9 +774,10 @@ inline bool has_header(const Headers& headers, const char* key) } inline const char* get_header_value( - const Headers& headers, const char* key, const char* def = nullptr) + const Headers& headers, const char* key, size_t id = 0, const char* def = nullptr) { auto it = headers.find(key); + std::advance(it, id); if (it != headers.end()) { return it->second.c_str(); } @@ -905,14 +909,14 @@ bool read_content(Stream& strm, T& x, Progress progress = Progress()) if (has_header(x.headers, "Content-Length")) { auto len = get_header_value_int(x.headers, "Content-Length", 0); if (len == 0) { - const auto& encoding = get_header_value(x.headers, "Transfer-Encoding", ""); + const auto& encoding = get_header_value(x.headers, "Transfer-Encoding", 0, ""); if (!strcasecmp(encoding, "chunked")) { return read_content_chunked(strm, x.body); } } return read_content_with_length(strm, x.body, len, progress); } else { - const auto& encoding = get_header_value(x.headers, "Transfer-Encoding", ""); + const auto& encoding = get_header_value(x.headers, "Transfer-Encoding", 0, ""); if (!strcasecmp(encoding, "chunked")) { return read_content_chunked(strm, x.body); } @@ -1333,9 +1337,15 @@ inline bool Request::has_header(const char* key) const return detail::has_header(headers, key); } -inline std::string Request::get_header_value(const char* key) const +inline std::string Request::get_header_value(const char* key, size_t id) const { - return detail::get_header_value(headers, key, ""); + return detail::get_header_value(headers, key, id, ""); +} + +inline size_t Request::get_header_value_count(const char* key) const +{ + auto r = headers.equal_range(key); + return std::distance(r.first, r.second); } inline void Request::set_header(const char* key, const char* val) @@ -1348,15 +1358,22 @@ inline bool Request::has_param(const char* key) const return params.find(key) != params.end(); } -inline std::string Request::get_param_value(const char* key) const +inline std::string Request::get_param_value(const char* key, size_t id) const { auto it = params.find(key); + std::advance(it, id); if (it != params.end()) { return it->second; } return std::string(); } +inline size_t Request::get_param_value_count(const char* key) const +{ + auto r = params.equal_range(key); + return std::distance(r.first, r.second); +} + inline bool Request::has_file(const char* key) const { return files.find(key) != files.end(); @@ -1377,9 +1394,15 @@ inline bool Response::has_header(const char* key) const return headers.find(key) != headers.end(); } -inline std::string Response::get_header_value(const char* key) const +inline std::string Response::get_header_value(const char* key, size_t id) const { - return detail::get_header_value(headers, key, ""); + return detail::get_header_value(headers, key, id, ""); +} + +inline size_t Response::get_header_value_count(const char* key) const +{ + auto r = headers.equal_range(key); + return std::distance(r.first, r.second); } inline void Response::set_header(const char* key, const char* val) diff --git a/test/test.cc b/test/test.cc index 5487db8..d87f104 100644 --- a/test/test.cc +++ b/test/test.cc @@ -71,7 +71,7 @@ TEST(ParseQueryTest, ParseQueryString) TEST(GetHeaderValueTest, DefaultValue) { Headers headers = {{"Dummy","Dummy"}}; - auto val = detail::get_header_value(headers, "Content-Type", "text/plain"); + auto val = detail::get_header_value(headers, "Content-Type", 0, "text/plain"); EXPECT_STREQ("text/plain", val); } @@ -85,7 +85,7 @@ TEST(GetHeaderValueTest, DefaultValueInt) TEST(GetHeaderValueTest, RegularValue) { Headers headers = {{"Content-Type", "text/html"}, {"Dummy", "Dummy"}}; - auto val = detail::get_header_value(headers, "Content-Type", "text/plain"); + auto val = detail::get_header_value(headers, "Content-Type", 0, "text/plain"); EXPECT_STREQ("text/html", val); } @@ -100,25 +100,25 @@ TEST(GetHeaderValueTest, Range) { { Headers headers = { make_range_header(1) }; - auto val = detail::get_header_value(headers, "Range", 0); + auto val = detail::get_header_value(headers, "Range", 0, 0); EXPECT_STREQ("bytes=1-", val); } { Headers headers = { make_range_header(1, 10) }; - auto val = detail::get_header_value(headers, "Range", 0); + auto val = detail::get_header_value(headers, "Range", 0, 0); EXPECT_STREQ("bytes=1-10", val); } { Headers headers = { make_range_header(1, 10, 100) }; - auto val = detail::get_header_value(headers, "Range", 0); + auto val = detail::get_header_value(headers, "Range", 0, 0); EXPECT_STREQ("bytes=1-10, 100-", val); } { Headers headers = { make_range_header(1, 10, 100, 200) }; - auto val = detail::get_header_value(headers, "Range", 0); + auto val = detail::get_header_value(headers, "Range", 0, 0); EXPECT_STREQ("bytes=1-10, 100-200", val); } } @@ -432,7 +432,12 @@ protected: EXPECT_EQ(LONG_QUERY_URL, req.target); EXPECT_EQ(LONG_QUERY_VALUE, req.get_param_value("key")); }) - + .Get("/array-param", [&](const Request& req, Response& /*res*/) { + EXPECT_EQ(3u, req.get_param_value_count("array")); + EXPECT_EQ("value1", req.get_param_value("array", 0)); + EXPECT_EQ("value2", req.get_param_value("array", 1)); + EXPECT_EQ("value3", req.get_param_value("array", 2)); + }) #ifdef CPPHTTPLIB_ZLIB_SUPPORT .Get("/gzip", [&](const Request& /*req*/, Response& res) { res.set_content("1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", "text/plain"); @@ -497,6 +502,7 @@ TEST_F(ServerTest, GetMethod200) EXPECT_EQ("HTTP/1.1", res->version); EXPECT_EQ(200, res->status); EXPECT_EQ("text/plain", res->get_header_value("Content-Type")); + EXPECT_EQ(1, res->get_header_value_count("Content-Type")); EXPECT_EQ("close", res->get_header_value("Connection")); EXPECT_EQ("Hello World!", res->body); } @@ -936,6 +942,13 @@ TEST_F(ServerTest, URL) EXPECT_EQ(200, res->status); } +TEST_F(ServerTest, ArrayParam) +{ + auto res = cli_.Get("/array-param?array=value1&array=value2&array=value3"); + ASSERT_TRUE(res != nullptr); + EXPECT_EQ(200, res->status); +} + #ifdef CPPHTTPLIB_ZLIB_SUPPORT TEST_F(ServerTest, Gzip) {