Fixed #32
This commit is contained in:
parent
459f197ed0
commit
31e53d21e4
@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
using namespace httplib;
|
using namespace httplib;
|
||||||
|
|
||||||
std::string dump_headers(const MultiMap& headers)
|
std::string dump_headers(const Headers& headers)
|
||||||
{
|
{
|
||||||
std::string s;
|
std::string s;
|
||||||
char buf[BUFSIZ];
|
char buf[BUFSIZ];
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
using namespace httplib;
|
using namespace httplib;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
string dump_headers(const MultiMap& headers)
|
string dump_headers(const Headers& headers)
|
||||||
{
|
{
|
||||||
string s;
|
string s;
|
||||||
char buf[BUFSIZ];
|
char buf[BUFSIZ];
|
||||||
|
47
httplib.h
47
httplib.h
@ -73,9 +73,25 @@ typedef int socket_t;
|
|||||||
namespace httplib
|
namespace httplib
|
||||||
{
|
{
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
struct ci {
|
||||||
|
bool operator() (const std::string & s1, const std::string & s2) const {
|
||||||
|
return std::lexicographical_compare(
|
||||||
|
s1.begin(), s1.end(),
|
||||||
|
s2.begin(), s2.end(),
|
||||||
|
[](char c1, char c2) {
|
||||||
|
return std::tolower(c1) < std::tolower(c2);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
enum class HttpVersion { v1_0 = 0, v1_1 };
|
enum class HttpVersion { v1_0 = 0, v1_1 };
|
||||||
|
|
||||||
typedef std::multimap<std::string, std::string> MultiMap;
|
typedef std::multimap<std::string, std::string, detail::ci> Headers;
|
||||||
|
typedef std::multimap<std::string, std::string> Params;
|
||||||
typedef std::smatch Match;
|
typedef std::smatch Match;
|
||||||
typedef std::function<void (int64_t current, int64_t total)> Progress;
|
typedef std::function<void (int64_t current, int64_t total)> Progress;
|
||||||
|
|
||||||
@ -90,9 +106,9 @@ typedef std::multimap<std::string, MultipartFile> MultipartFiles;
|
|||||||
struct Request {
|
struct Request {
|
||||||
std::string method;
|
std::string method;
|
||||||
std::string path;
|
std::string path;
|
||||||
MultiMap headers;
|
Headers headers;
|
||||||
std::string body;
|
std::string body;
|
||||||
MultiMap params;
|
Params params;
|
||||||
MultipartFiles files;
|
MultipartFiles files;
|
||||||
Match matches;
|
Match matches;
|
||||||
Progress progress;
|
Progress progress;
|
||||||
@ -110,7 +126,7 @@ struct Request {
|
|||||||
|
|
||||||
struct Response {
|
struct Response {
|
||||||
int status;
|
int status;
|
||||||
MultiMap headers;
|
Headers headers;
|
||||||
std::string body;
|
std::string body;
|
||||||
|
|
||||||
bool has_header(const char* key) const;
|
bool has_header(const char* key) const;
|
||||||
@ -198,7 +214,7 @@ public:
|
|||||||
std::shared_ptr<Response> get(const char* path, Progress callback = [](int64_t,int64_t){});
|
std::shared_ptr<Response> get(const char* path, Progress callback = [](int64_t,int64_t){});
|
||||||
std::shared_ptr<Response> head(const char* path);
|
std::shared_ptr<Response> head(const char* path);
|
||||||
std::shared_ptr<Response> post(const char* path, const std::string& body, const char* content_type);
|
std::shared_ptr<Response> post(const char* path, const std::string& body, const char* content_type);
|
||||||
std::shared_ptr<Response> post(const char* path, const MultiMap& params);
|
std::shared_ptr<Response> post(const char* path, const Params& params);
|
||||||
|
|
||||||
bool send(const Request& req, Response& res);
|
bool send(const Request& req, Response& res);
|
||||||
|
|
||||||
@ -562,7 +578,7 @@ inline const char* status_message(int status)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const char* get_header_value(const MultiMap& headers, const char* key, const char* def)
|
inline const char* get_header_value(const Headers& headers, const char* key, const char* def)
|
||||||
{
|
{
|
||||||
auto it = headers.find(key);
|
auto it = headers.find(key);
|
||||||
if (it != headers.end()) {
|
if (it != headers.end()) {
|
||||||
@ -571,7 +587,7 @@ inline const char* get_header_value(const MultiMap& headers, const char* key, co
|
|||||||
return def;
|
return def;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int get_header_value_int(const MultiMap& headers, const char* key, int def)
|
inline int get_header_value_int(const Headers& headers, const char* key, int def)
|
||||||
{
|
{
|
||||||
auto it = headers.find(key);
|
auto it = headers.find(key);
|
||||||
if (it != headers.end()) {
|
if (it != headers.end()) {
|
||||||
@ -580,7 +596,7 @@ inline int get_header_value_int(const MultiMap& headers, const char* key, int de
|
|||||||
return def;
|
return def;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool read_headers(Stream& strm, MultiMap& headers)
|
inline bool read_headers(Stream& strm, Headers& headers)
|
||||||
{
|
{
|
||||||
static std::regex re("(.+?): (.+?)\r\n");
|
static std::regex re("(.+?): (.+?)\r\n");
|
||||||
|
|
||||||
@ -853,7 +869,7 @@ inline std::string decode_url(const std::string& s)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void parse_query_text(const std::string& s, MultiMap& params)
|
inline void parse_query_text(const std::string& s, Params& params)
|
||||||
{
|
{
|
||||||
split(&s[0], &s[s.size()], '&', [&](const char* b, const char* e) {
|
split(&s[0], &s[s.size()], '&', [&](const char* b, const char* e) {
|
||||||
std::string key;
|
std::string key;
|
||||||
@ -980,6 +996,17 @@ public:
|
|||||||
static WSInit wsinit_;
|
static WSInit wsinit_;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
inline std::string to_lower(const char* beg, const char* end)
|
||||||
|
{
|
||||||
|
std::string out;
|
||||||
|
auto it = beg;
|
||||||
|
while (it != end) {
|
||||||
|
out += ::tolower(*it);
|
||||||
|
it++;
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
// Request implementation
|
// Request implementation
|
||||||
@ -1497,7 +1524,7 @@ inline std::shared_ptr<Response> Client::post(
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline std::shared_ptr<Response> Client::post(
|
inline std::shared_ptr<Response> Client::post(
|
||||||
const char* path, const MultiMap& params)
|
const char* path, const Params& params)
|
||||||
{
|
{
|
||||||
std::string query;
|
std::string query;
|
||||||
for (auto it = params.begin(); it != params.end(); ++it) {
|
for (auto it = params.begin(); it != params.end(); ++it) {
|
||||||
|
23
test/test.cc
23
test/test.cc
@ -32,7 +32,7 @@ TEST(StartupTest, WSAStartup)
|
|||||||
TEST(SplitTest, ParseQueryString)
|
TEST(SplitTest, ParseQueryString)
|
||||||
{
|
{
|
||||||
string s = "key1=val1&key2=val2&key3=val3";
|
string s = "key1=val1&key2=val2&key3=val3";
|
||||||
MultiMap dic;
|
Params dic;
|
||||||
|
|
||||||
detail::split(s.c_str(), s.c_str() + s.size(), '&', [&](const char* b, const char* e) {
|
detail::split(s.c_str(), s.c_str() + s.size(), '&', [&](const char* b, const char* e) {
|
||||||
string key, val;
|
string key, val;
|
||||||
@ -54,7 +54,7 @@ TEST(SplitTest, ParseQueryString)
|
|||||||
TEST(ParseQueryTest, ParseQueryString)
|
TEST(ParseQueryTest, ParseQueryString)
|
||||||
{
|
{
|
||||||
string s = "key1=val1&key2=val2&key3=val3";
|
string s = "key1=val1&key2=val2&key3=val3";
|
||||||
MultiMap dic;
|
Params dic;
|
||||||
|
|
||||||
detail::parse_query_text(s, dic);
|
detail::parse_query_text(s, dic);
|
||||||
|
|
||||||
@ -83,28 +83,28 @@ TEST(SocketTest, OpenCloseWithAI_PASSIVE)
|
|||||||
|
|
||||||
TEST(GetHeaderValueTest, DefaultValue)
|
TEST(GetHeaderValueTest, DefaultValue)
|
||||||
{
|
{
|
||||||
MultiMap map = {{"Dummy","Dummy"}};
|
Headers map = {{"Dummy","Dummy"}};
|
||||||
auto val = detail::get_header_value(map, "Content-Type", "text/plain");
|
auto val = detail::get_header_value(map, "Content-Type", "text/plain");
|
||||||
ASSERT_STREQ("text/plain", val);
|
ASSERT_STREQ("text/plain", val);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(GetHeaderValueTest, DefaultValueInt)
|
TEST(GetHeaderValueTest, DefaultValueInt)
|
||||||
{
|
{
|
||||||
MultiMap map = {{"Dummy","Dummy"}};
|
Headers map = {{"Dummy","Dummy"}};
|
||||||
auto val = detail::get_header_value_int(map, "Content-Length", 100);
|
auto val = detail::get_header_value_int(map, "Content-Length", 100);
|
||||||
EXPECT_EQ(100, val);
|
EXPECT_EQ(100, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(GetHeaderValueTest, RegularValue)
|
TEST(GetHeaderValueTest, RegularValue)
|
||||||
{
|
{
|
||||||
MultiMap map = {{"Content-Type", "text/html"}, {"Dummy", "Dummy"}};
|
Headers map = {{"Content-Type", "text/html"}, {"Dummy", "Dummy"}};
|
||||||
auto val = detail::get_header_value(map, "Content-Type", "text/plain");
|
auto val = detail::get_header_value(map, "Content-Type", "text/plain");
|
||||||
ASSERT_STREQ("text/html", val);
|
ASSERT_STREQ("text/html", val);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(GetHeaderValueTest, RegularValueInt)
|
TEST(GetHeaderValueTest, RegularValueInt)
|
||||||
{
|
{
|
||||||
MultiMap map = {{"Content-Length", "100"}, {"Dummy", "Dummy"}};
|
Headers map = {{"Content-Length", "100"}, {"Dummy", "Dummy"}};
|
||||||
auto val = detail::get_header_value_int(map, "Content-Length", 0);
|
auto val = detail::get_header_value_int(map, "Content-Length", 0);
|
||||||
EXPECT_EQ(100, val);
|
EXPECT_EQ(100, val);
|
||||||
}
|
}
|
||||||
@ -310,7 +310,7 @@ TEST_F(ServerTest, PostMethod2)
|
|||||||
ASSERT_TRUE(res != nullptr);
|
ASSERT_TRUE(res != nullptr);
|
||||||
ASSERT_EQ(404, res->status);
|
ASSERT_EQ(404, res->status);
|
||||||
|
|
||||||
MultiMap params;
|
Params params;
|
||||||
params.emplace("name", "john2");
|
params.emplace("name", "john2");
|
||||||
params.emplace("note", "coder");
|
params.emplace("note", "coder");
|
||||||
|
|
||||||
@ -512,6 +512,15 @@ TEST_F(ServerTest, MultipartFormData)
|
|||||||
EXPECT_EQ(200, res->status);
|
EXPECT_EQ(200, res->status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(ServerTest, CaseInsensitiveHeaderName)
|
||||||
|
{
|
||||||
|
auto res = cli_.get("/hi");
|
||||||
|
ASSERT_TRUE(res != nullptr);
|
||||||
|
EXPECT_EQ(200, res->status);
|
||||||
|
EXPECT_EQ("text/plain", res->get_header_value("content-type"));
|
||||||
|
EXPECT_EQ("Hello World!", res->body);
|
||||||
|
}
|
||||||
|
|
||||||
class ServerTestWithAI_PASSIVE : public ::testing::Test {
|
class ServerTestWithAI_PASSIVE : public ::testing::Test {
|
||||||
protected:
|
protected:
|
||||||
ServerTestWithAI_PASSIVE()
|
ServerTestWithAI_PASSIVE()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user