Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

a #1

Merged
merged 13 commits into from
Feb 19, 2019
Prev Previous commit
Next Next commit
  • Loading branch information
yhirose committed Dec 18, 2018
commit b5927aec123351dcf796e1fba8a6a1805d294cbe
45 changes: 34 additions & 11 deletions httplib.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -150,7 +152,8 @@ struct Response {
std::function<std::string (uint64_t offset)> 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);
Expand Down Expand Up @@ -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();
}
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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)
Expand All @@ -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();
Expand All @@ -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, 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)
Expand Down
27 changes: 20 additions & 7 deletions test/test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand All @@ -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);
}

Expand All @@ -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);
}
}
Expand Down Expand Up @@ -432,7 +432,12 @@ class ServerTest : public ::testing::Test {
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");
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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)
{
Expand Down