yhirose 7 years ago
parent
commit
b5927aec12
2 changed files with 54 additions and 18 deletions
  1. 34 11
      httplib.h
  2. 20 7
      test/test.cc

+ 34 - 11
httplib.h

@@ -132,11 +132,13 @@ struct Request {
     Progress       progress;
     Progress       progress;
 
 
     bool has_header(const char* key) const;
     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_header(const char* key, const char* val);
 
 
     bool has_param(const char* key) const;
     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;
     bool has_file(const char* key) const;
     MultipartFile get_file_value(const char* key) const;
     MultipartFile get_file_value(const char* key) const;
@@ -150,7 +152,8 @@ struct Response {
     std::function<std::string (uint64_t offset)> streamcb;
     std::function<std::string (uint64_t offset)> streamcb;
 
 
     bool has_header(const char* key) const;
     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_header(const char* key, const char* val);
 
 
     void set_redirect(const char* uri);
     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(
 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);
     auto it = headers.find(key);
+    std::advance(it, id);
     if (it != headers.end()) {
     if (it != headers.end()) {
         return it->second.c_str();
         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")) {
     if (has_header(x.headers, "Content-Length")) {
         auto len = get_header_value_int(x.headers, "Content-Length", 0);
         auto len = get_header_value_int(x.headers, "Content-Length", 0);
         if (len == 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")) {
             if (!strcasecmp(encoding, "chunked")) {
                 return read_content_chunked(strm, x.body);
                 return read_content_chunked(strm, x.body);
             }
             }
         }
         }
         return read_content_with_length(strm, x.body, len, progress);
         return read_content_with_length(strm, x.body, len, progress);
     } else {
     } 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")) {
         if (!strcasecmp(encoding, "chunked")) {
             return read_content_chunked(strm, x.body);
             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);
     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)
 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();
     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);
     auto it = params.find(key);
+    std::advance(it, id);
     if (it != params.end()) {
     if (it != params.end()) {
         return it->second;
         return it->second;
     }
     }
     return std::string();
     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
 inline bool Request::has_file(const char* key) const
 {
 {
     return files.find(key) != files.end();
     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();
     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, id, "");
+}
+
+inline size_t Response::get_header_value_count(const char* key) const
 {
 {
-    return detail::get_header_value(headers, key, "");
+    auto r = headers.equal_range(key);
+    return std::distance(r.first, r.second);
 }
 }
 
 
 inline void Response::set_header(const char* key, const char* val)
 inline void Response::set_header(const char* key, const char* val)

+ 20 - 7
test/test.cc

@@ -71,7 +71,7 @@ TEST(ParseQueryTest, ParseQueryString)
 TEST(GetHeaderValueTest, DefaultValue)
 TEST(GetHeaderValueTest, DefaultValue)
 {
 {
     Headers headers = {{"Dummy","Dummy"}};
     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);
     EXPECT_STREQ("text/plain", val);
 }
 }
 
 
@@ -85,7 +85,7 @@ TEST(GetHeaderValueTest, DefaultValueInt)
 TEST(GetHeaderValueTest, RegularValue)
 TEST(GetHeaderValueTest, RegularValue)
 {
 {
     Headers headers = {{"Content-Type", "text/html"}, {"Dummy", "Dummy"}};
     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);
     EXPECT_STREQ("text/html", val);
 }
 }
 
 
@@ -100,25 +100,25 @@ TEST(GetHeaderValueTest, Range)
 {
 {
     {
     {
         Headers headers = { make_range_header(1) };
         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);
         EXPECT_STREQ("bytes=1-", val);
     }
     }
 
 
     {
     {
         Headers headers = { make_range_header(1, 10) };
         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);
         EXPECT_STREQ("bytes=1-10", val);
     }
     }
 
 
     {
     {
         Headers headers = { make_range_header(1, 10, 100) };
         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);
         EXPECT_STREQ("bytes=1-10, 100-", val);
     }
     }
 
 
     {
     {
         Headers headers = { make_range_header(1, 10, 100, 200) };
         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);
         EXPECT_STREQ("bytes=1-10, 100-200", val);
     }
     }
 }
 }
@@ -432,7 +432,12 @@ protected:
                 EXPECT_EQ(LONG_QUERY_URL, req.target);
                 EXPECT_EQ(LONG_QUERY_URL, req.target);
                 EXPECT_EQ(LONG_QUERY_VALUE, req.get_param_value("key"));
                 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
 #ifdef CPPHTTPLIB_ZLIB_SUPPORT
             .Get("/gzip", [&](const Request& /*req*/, Response& res) {
             .Get("/gzip", [&](const Request& /*req*/, Response& res) {
                 res.set_content("1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", "text/plain");
                 res.set_content("1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", "text/plain");
@@ -497,6 +502,7 @@ TEST_F(ServerTest, GetMethod200)
     EXPECT_EQ("HTTP/1.1", res->version);
     EXPECT_EQ("HTTP/1.1", res->version);
     EXPECT_EQ(200, res->status);
     EXPECT_EQ(200, res->status);
     EXPECT_EQ("text/plain", res->get_header_value("Content-Type"));
     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("close", res->get_header_value("Connection"));
     EXPECT_EQ("Hello World!", res->body);
     EXPECT_EQ("Hello World!", res->body);
 }
 }
@@ -936,6 +942,13 @@ TEST_F(ServerTest, URL)
     EXPECT_EQ(200, res->status);
     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
 #ifdef CPPHTTPLIB_ZLIB_SUPPORT
 TEST_F(ServerTest, Gzip)
 TEST_F(ServerTest, Gzip)
 {
 {