diff --git a/README.md b/README.md index 291e4bd..0c4fb2d 100644 --- a/README.md +++ b/README.md @@ -19,11 +19,11 @@ int main(void) Server svr; - svr.get("/hi", [](const Request& req, Response& res) { + svr.Get("/hi", [](const Request& req, Response& res) { res.set_content("Hello World!", "text/plain"); }); - svr.get(R"(/numbers/(\d+))", [&](const Request& req, Response& res) { + svr.Get(R"(/numbers/(\d+))", [&](const Request& req, Response& res) { auto numbers = req.matches[1]; res.set_content(numbers, "text/plain"); }); @@ -32,13 +32,15 @@ int main(void) } ``` +`Post`, `Put`, `Delete` and `Options` methods are also supported. + ### Method Chain ```cpp -svr.get("/get", [](const auto& req, auto& res) { +svr.Get("/get", [](const auto& req, auto& res) { res.set_content("get", "text/plain"); }) - .post("/post", [](const auto& req, auto& res) { + .Post("/post", [](const auto& req, auto& res) { res.set_content(req.body(), "text/plain"); }) .listen("localhost", 1234); @@ -72,7 +74,7 @@ svr.set_error_handler([](const auto& req, auto& res) { ### 'multipart/form-data' POST data ```cpp -svr.post("/multipart", [&](const auto& req, auto& res) { +svr.Post("/multipart", [&](const auto& req, auto& res) { auto size = req.files.size(); auto ret = req.has_file("name1")); const auto& file = req.get_file_value("name1"); @@ -95,7 +97,7 @@ int main(void) { httplib::Client cli("localhost", 1234); - auto res = cli.get("/hi"); + auto res = cli.Get("/hi"); if (res && res->status == 200) { std::cout << res->body << std::endl; } @@ -105,8 +107,8 @@ int main(void) ### POST ```c++ -res = cli.post("/post", "text", "text/plain"); -res = cli.post("/person", "name=john1¬e=coder", "application/x-www-form-urlencoded"); +res = cli.Post("/post", "text", "text/plain"); +res = cli.Post("/person", "name=john1¬e=coder", "application/x-www-form-urlencoded"); ``` ### POST with parameters @@ -115,7 +117,26 @@ res = cli.post("/person", "name=john1¬e=coder", "application/x-www-form-urlen httplib::Map params; params["name"] = "john"; params["note"] = "coder"; -auto res = cli.post("/post", params); +auto res = cli.Post("/post", params); +``` + +### PUT + +```c++ +res = cli.Post("/resource/foo", "text", "text/plain"); +``` + +### DELETE + +```c++ +res = cli.Delete("/resource/foo"); +``` + +### OPTIONS + +```c++ +res = cli.Options("*"); +res = cli.Options("/resource/foo"); ``` ### Connection Timeout @@ -130,7 +151,7 @@ httplib::Client client(url, port); // prints: 0 / 000 bytes => 50% complete std::shared_ptr res = - cli.get("/", [](uint64_t len, uint64_t total) { + cli.Get("/", [](uint64_t len, uint64_t total) { printf("%lld / %lld bytes => %d%% complete\n", len, total, (int)((len/total)*100)); @@ -150,7 +171,7 @@ httplib::Client cli("httpbin.org", 80); // 'Range: bytes=1-10' httplib::Headers headers = { httplib::make_range_header(1, 10) }; -auto res = cli.get("/range/32", headers); +auto res = cli.Get("/range/32", headers); // res->status should be 206. // res->body should be "bcdefghijk". ``` @@ -185,4 +206,4 @@ The server applies gzip compression to the following MIME type contents: License ------- -MIT license (© 2017 Yuji Hirose) +MIT license (© 2018 Yuji Hirose) diff --git a/example/benchmark.cc b/example/benchmark.cc index 9d09df1..d4092f5 100644 --- a/example/benchmark.cc +++ b/example/benchmark.cc @@ -25,7 +25,7 @@ int main(void) { for (int i = 0; i < 3; i++) { StopWatch sw(to_string(i).c_str()); - auto res = cli.post("/post", body, "application/octet-stream"); + auto res = cli.Post("/post", body, "application/octet-stream"); assert(res->status == 200); } diff --git a/example/client.cc b/example/client.cc index 3bd1641..d3ad4ba 100644 --- a/example/client.cc +++ b/example/client.cc @@ -18,7 +18,7 @@ int main(void) httplib::Client cli("localhost", 8080); #endif - auto res = cli.get("/hi"); + auto res = cli.Get("/hi"); if (res) { cout << res->status << endl; cout << res->get_header_value("Content-Type") << endl; diff --git a/example/hello.cc b/example/hello.cc index 3b0c7f6..f315511 100644 --- a/example/hello.cc +++ b/example/hello.cc @@ -12,7 +12,7 @@ int main(void) { Server svr; - svr.get("/hi", [](const auto& /*req*/, auto& res) { + svr.Get("/hi", [](const auto& /*req*/, auto& res) { res.set_content("Hello World!", "text/plain"); }); diff --git a/example/server.cc b/example/server.cc index b8eb510..bd24b35 100644 --- a/example/server.cc +++ b/example/server.cc @@ -81,25 +81,25 @@ int main(void) return -1; } - svr.get("/", [=](const auto& /*req*/, auto& res) { + svr.Get("/", [=](const auto& /*req*/, auto& res) { res.set_redirect("/hi"); }); - svr.get("/hi", [](const auto& /*req*/, auto& res) { + svr.Get("/hi", [](const auto& /*req*/, auto& res) { res.set_content("Hello World!\n", "text/plain"); }); - svr.get("/slow", [](const auto& /*req*/, auto& res) { + svr.Get("/slow", [](const auto& /*req*/, auto& res) { using namespace std::chrono_literals; std::this_thread::sleep_for(2s); res.set_content("Slow...\n", "text/plain"); }); - svr.get("/dump", [](const auto& req, auto& res) { + svr.Get("/dump", [](const auto& req, auto& res) { res.set_content(dump_headers(req.headers), "text/plain"); }); - svr.get("/stop", [&](const auto& /*req*/, auto& /*res*/) { + svr.Get("/stop", [&](const auto& /*req*/, auto& /*res*/) { svr.stop(); }); diff --git a/example/simplesvr.cc b/example/simplesvr.cc index 8a590a2..daeb90a 100644 --- a/example/simplesvr.cc +++ b/example/simplesvr.cc @@ -107,7 +107,7 @@ int main(int argc, const char** argv) Server svr(version); #endif - svr.post("/multipart", [](const auto& req, auto& res) { + svr.Post("/multipart", [](const auto& req, auto& res) { auto body = dump_headers(req.headers) + dump_multipart_files(req.files); diff --git a/httplib.h b/httplib.h index ae3df2e..a5eeaa2 100644 --- a/httplib.h +++ b/httplib.h @@ -194,8 +194,12 @@ public: virtual bool is_valid() const; - Server& get(const char* pattern, Handler handler); - Server& post(const char* pattern, Handler handler); + Server& Get(const char* pattern, Handler handler); + Server& Post(const char* pattern, Handler handler); + + Server& Put(const char* pattern, Handler handler); + Server& Delete(const char* pattern, Handler handler); + Server& Options(const char* pattern, Handler handler); bool set_base_dir(const char* path); @@ -236,6 +240,9 @@ private: std::string base_dir_; Handlers get_handlers_; Handlers post_handlers_; + Handlers put_handlers_; + Handlers delete_handlers_; + Handlers options_handlers_; Handler error_handler_; Logger logger_; @@ -256,17 +263,26 @@ public: virtual bool is_valid() const; - std::shared_ptr get(const char* path, Progress progress = nullptr); - std::shared_ptr get(const char* path, const Headers& headers, Progress progress = nullptr); + std::shared_ptr Get(const char* path, Progress progress = nullptr); + std::shared_ptr Get(const char* path, const Headers& headers, Progress progress = nullptr); - std::shared_ptr head(const char* path); - std::shared_ptr head(const char* path, const Headers& headers); + std::shared_ptr Head(const char* path); + std::shared_ptr Head(const char* path, const Headers& headers); - std::shared_ptr post(const char* path, const std::string& body, const char* content_type); - std::shared_ptr post(const char* path, const Headers& headers, const std::string& body, const char* content_type); + std::shared_ptr Post(const char* path, const std::string& body, const char* content_type); + std::shared_ptr Post(const char* path, const Headers& headers, const std::string& body, const char* content_type); - std::shared_ptr post(const char* path, const Params& params); - std::shared_ptr post(const char* path, const Headers& headers, const Params& params); + std::shared_ptr Post(const char* path, const Params& params); + std::shared_ptr Post(const char* path, const Headers& headers, const Params& params); + + std::shared_ptr Put(const char* path, const std::string& body, const char* content_type); + std::shared_ptr Put(const char* path, const Headers& headers, const std::string& body, const char* content_type); + + std::shared_ptr Delete(const char* path); + std::shared_ptr Delete(const char* path, const Headers& headers); + + std::shared_ptr Options(const char* path); + std::shared_ptr Options(const char* path, const Headers& headers); bool send(Request& req, Response& res); @@ -1411,18 +1427,36 @@ inline Server::~Server() { } -inline Server& Server::get(const char* pattern, Handler handler) +inline Server& Server::Get(const char* pattern, Handler handler) { get_handlers_.push_back(std::make_pair(std::regex(pattern), handler)); return *this; } -inline Server& Server::post(const char* pattern, Handler handler) +inline Server& Server::Post(const char* pattern, Handler handler) { post_handlers_.push_back(std::make_pair(std::regex(pattern), handler)); return *this; } +inline Server& Server::Put(const char* pattern, Handler handler) +{ + put_handlers_.push_back(std::make_pair(std::regex(pattern), handler)); + return *this; +} + +inline Server& Server::Delete(const char* pattern, Handler handler) +{ + delete_handlers_.push_back(std::make_pair(std::regex(pattern), handler)); + return *this; +} + +inline Server& Server::Options(const char* pattern, Handler handler) +{ + options_handlers_.push_back(std::make_pair(std::regex(pattern), handler)); + return *this; +} + inline bool Server::set_base_dir(const char* path) { if (detail::is_dir(path)) { @@ -1475,7 +1509,7 @@ inline void Server::stop() inline bool Server::parse_request_line(const char* s, Request& req) { - static std::regex re("(GET|HEAD|POST) ([^?]+)(?:\\?(.+?))? (HTTP/1\\.[01])\r\n"); + static std::regex re("(GET|HEAD|POST|PUT|DELETE|OPTIONS) ([^?]+)(?:\\?(.+?))? (HTTP/1\\.[01])\r\n"); std::cmatch m; if (std::regex_match(s, m, re)) { @@ -1675,6 +1709,12 @@ inline bool Server::routing(Request& req, Response& res) return dispatch_request(req, res, get_handlers_); } else if (req.method == "POST") { return dispatch_request(req, res, post_handlers_); + } else if (req.method == "PUT") { + return dispatch_request(req, res, put_handlers_); + } else if (req.method == "DELETE") { + return dispatch_request(req, res, delete_handlers_); + } else if (req.method == "OPTIONS") { + return dispatch_request(req, res, options_handlers_); } return false; } @@ -1725,7 +1765,7 @@ inline bool Server::process_request(Stream& strm, bool last_connection) req.set_header("REMOTE_ADDR", strm.get_remote_addr().c_str()); // Body - if (req.method == "POST") { + if (req.method == "POST" || req.method == "PUT") { if (!detail::read_content(strm, req)) { res.status = 400; write_response(strm, last_connection, req, res); @@ -1947,12 +1987,12 @@ inline bool Client::read_and_close_socket(socket_t sock, Request& req, Response& }); } -inline std::shared_ptr Client::get(const char* path, Progress progress) +inline std::shared_ptr Client::Get(const char* path, Progress progress) { - return get(path, Headers(), progress); + return Get(path, Headers(), progress); } -inline std::shared_ptr Client::get(const char* path, const Headers& headers, Progress progress) +inline std::shared_ptr Client::Get(const char* path, const Headers& headers, Progress progress) { Request req; req.method = "GET"; @@ -1965,12 +2005,12 @@ inline std::shared_ptr Client::get(const char* path, const Headers& he return send(req, *res) ? res : nullptr; } -inline std::shared_ptr Client::head(const char* path) +inline std::shared_ptr Client::Head(const char* path) { - return head(path, Headers()); + return Head(path, Headers()); } -inline std::shared_ptr Client::head(const char* path, const Headers& headers) +inline std::shared_ptr Client::Head(const char* path, const Headers& headers) { Request req; req.method = "HEAD"; @@ -1982,13 +2022,13 @@ inline std::shared_ptr Client::head(const char* path, const Headers& h return send(req, *res) ? res : nullptr; } -inline std::shared_ptr Client::post( +inline std::shared_ptr Client::Post( const char* path, const std::string& body, const char* content_type) { - return post(path, Headers(), body, content_type); + return Post(path, Headers(), body, content_type); } -inline std::shared_ptr Client::post( +inline std::shared_ptr Client::Post( const char* path, const Headers& headers, const std::string& body, const char* content_type) { Request req; @@ -2004,12 +2044,12 @@ inline std::shared_ptr Client::post( return send(req, *res) ? res : nullptr; } -inline std::shared_ptr Client::post(const char* path, const Params& params) +inline std::shared_ptr Client::Post(const char* path, const Params& params) { - return post(path, Headers(), params); + return Post(path, Headers(), params); } -inline std::shared_ptr Client::post(const char* path, const Headers& headers, const Params& params) +inline std::shared_ptr Client::Post(const char* path, const Headers& headers, const Params& params) { std::string query; for (auto it = params.begin(); it != params.end(); ++it) { @@ -2021,7 +2061,63 @@ inline std::shared_ptr Client::post(const char* path, const Headers& h query += it->second; } - return post(path, headers, query, "application/x-www-form-urlencoded"); + return Post(path, headers, query, "application/x-www-form-urlencoded"); +} + +inline std::shared_ptr Client::Put( + const char* path, const std::string& body, const char* content_type) +{ + return Put(path, Headers(), body, content_type); +} + +inline std::shared_ptr Client::Put( + const char* path, const Headers& headers, const std::string& body, const char* content_type) +{ + Request req; + req.method = "PUT"; + req.headers = headers; + req.path = path; + + req.headers.emplace("Content-Type", content_type); + req.body = body; + + auto res = std::make_shared(); + + return send(req, *res) ? res : nullptr; +} + +inline std::shared_ptr Client::Delete(const char* path) +{ + return Delete(path, Headers()); +} + +inline std::shared_ptr Client::Delete(const char* path, const Headers& headers) +{ + Request req; + req.method = "DELETE"; + req.path = path; + req.headers = headers; + + auto res = std::make_shared(); + + return send(req, *res) ? res : nullptr; +} + +inline std::shared_ptr Client::Options(const char* path) +{ + return Options(path, Headers()); +} + +inline std::shared_ptr Client::Options(const char* path, const Headers& headers) +{ + Request req; + req.method = "OPTIONS"; + req.path = path; + req.headers = headers; + + auto res = std::make_shared(); + + return send(req, *res) ? res : nullptr; } /* diff --git a/test/test.cc b/test/test.cc index 1d0a2af..2330683 100644 --- a/test/test.cc +++ b/test/test.cc @@ -131,7 +131,7 @@ void testChunkedEncoding(httplib::HttpVersion ver) httplib::Client cli(host, port, sec, ver); #endif - auto res = cli.get("/httpgallery/chunked/chunkedimage.aspx?0.4153841143030137"); + auto res = cli.Get("/httpgallery/chunked/chunkedimage.aspx?0.4153841143030137"); ASSERT_TRUE(res != nullptr); std::string out; @@ -163,7 +163,7 @@ TEST(RangeTest, FromHTTPBin) { httplib::Headers headers; - auto res = cli.get("/range/32", headers); + auto res = cli.Get("/range/32", headers); ASSERT_TRUE(res != nullptr); EXPECT_EQ(res->body, "abcdefghijklmnopqrstuvwxyzabcdef"); EXPECT_EQ(200, res->status); @@ -171,7 +171,7 @@ TEST(RangeTest, FromHTTPBin) { httplib::Headers headers = { httplib::make_range_header(1) }; - auto res = cli.get("/range/32", headers); + auto res = cli.Get("/range/32", headers); ASSERT_TRUE(res != nullptr); EXPECT_EQ(res->body, "bcdefghijklmnopqrstuvwxyzabcdef"); EXPECT_EQ(206, res->status); @@ -179,7 +179,7 @@ TEST(RangeTest, FromHTTPBin) { httplib::Headers headers = { httplib::make_range_header(1, 10) }; - auto res = cli.get("/range/32", headers); + auto res = cli.Get("/range/32", headers); ASSERT_TRUE(res != nullptr); EXPECT_EQ(res->body, "bcdefghijk"); EXPECT_EQ(206, res->status); @@ -200,7 +200,7 @@ TEST(ConnectionErrorTest, InvalidHost) httplib::Client cli(host, port, sec, ver); #endif - auto res = cli.get("/"); + auto res = cli.Get("/"); ASSERT_TRUE(res == nullptr); } @@ -218,7 +218,7 @@ TEST(ConnectionErrorTest, InvalidPort) httplib::Client cli(host, port, sec, ver); #endif - auto res = cli.get("/"); + auto res = cli.Get("/"); ASSERT_TRUE(res == nullptr); } @@ -236,7 +236,7 @@ TEST(ConnectionErrorTest, Timeout) httplib::Client cli(host, port, sec, ver); #endif - auto res = cli.get("/"); + auto res = cli.Get("/"); ASSERT_TRUE(res == nullptr); } @@ -259,31 +259,31 @@ protected: virtual void SetUp() { svr_.set_base_dir("./www"); - svr_.get("/hi", [&](const Request& /*req*/, Response& res) { + svr_.Get("/hi", [&](const Request& /*req*/, Response& res) { res.set_content("Hello World!", "text/plain"); }) - .get("/slow", [&](const Request& /*req*/, Response& res) { + .Get("/slow", [&](const Request& /*req*/, Response& res) { msleep(2000); res.set_content("slow", "text/plain"); }) - .get("/remote_addr", [&](const Request& req, Response& res) { + .Get("/remote_addr", [&](const Request& req, Response& res) { auto remote_addr = req.headers.find("REMOTE_ADDR")->second; res.set_content(remote_addr.c_str(), "text/plain"); }) - .get("/endwith%", [&](const Request& /*req*/, Response& res) { + .Get("/endwith%", [&](const Request& /*req*/, Response& res) { res.set_content("Hello World!", "text/plain"); }) - .get("/", [&](const Request& /*req*/, Response& res) { + .Get("/", [&](const Request& /*req*/, Response& res) { res.set_redirect("/hi"); }) - .post("/person", [&](const Request& req, Response& res) { + .Post("/person", [&](const Request& req, Response& res) { if (req.has_param("name") && req.has_param("note")) { persons_[req.get_param_value("name")] = req.get_param_value("note"); } else { res.status = 400; } }) - .get("/person/(.*)", [&](const Request& req, Response& res) { + .Get("/person/(.*)", [&](const Request& req, Response& res) { string name = req.matches[1]; if (persons_.find(name) != persons_.end()) { auto note = persons_[name]; @@ -292,14 +292,14 @@ protected: res.status = 404; } }) - .post("/chunked", [&](const Request& req, Response& /*res*/) { + .Post("/chunked", [&](const Request& req, Response& /*res*/) { EXPECT_EQ(req.body, "dechunked post body"); }) - .post("/largechunked", [&](const Request& req, Response& /*res*/) { + .Post("/largechunked", [&](const Request& req, Response& /*res*/) { std::string expected(6 * 30 * 1024u, 'a'); EXPECT_EQ(req.body, expected); }) - .post("/multipart", [&](const Request& req, Response& /*res*/) { + .Post("/multipart", [&](const Request& req, Response& /*res*/) { EXPECT_EQ(5u, req.files.size()); ASSERT_TRUE(!req.has_file("???")); @@ -329,14 +329,24 @@ protected: EXPECT_EQ(0u, file.length); } }) + .Put("/put", [&](const Request& req, Response& res) { + EXPECT_EQ(req.body, "PUT"); + res.set_content(req.body, "text/plain"); + }) + .Delete("/delete", [&](const Request& /*req*/, Response& res) { + res.set_content("DELETE", "text/plain"); + }) + .Options(R"(\*)", [&](const Request& /*req*/, Response& res) { + res.set_header("Allow", "GET, POST, HEAD, OPTIONS"); + }) #ifdef CPPHTTPLIB_ZLIB_SUPPORT - .get("/gzip", [&](const Request& /*req*/, Response& res) { + .Get("/gzip", [&](const Request& /*req*/, Response& res) { res.set_content("1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", "text/plain"); }) - .get("/nogzip", [&](const Request& /*req*/, Response& res) { + .Get("/nogzip", [&](const Request& /*req*/, Response& res) { res.set_content("1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", "application/octet-stream"); }) - .post("/gzipmultipart", [&](const Request& req, Response& /*res*/) { + .Post("/gzipmultipart", [&](const Request& req, Response& /*res*/) { EXPECT_EQ(2u, req.files.size()); ASSERT_TRUE(!req.has_file("???")); @@ -388,7 +398,7 @@ protected: TEST_F(ServerTest, GetMethod200) { - auto res = cli_.get("/hi"); + auto res = cli_.Get("/hi"); ASSERT_TRUE(res != nullptr); EXPECT_EQ(200, res->status); EXPECT_EQ("text/plain", res->get_header_value("Content-Type")); @@ -397,7 +407,7 @@ TEST_F(ServerTest, GetMethod200) TEST_F(ServerTest, GetMethod302) { - auto res = cli_.get("/"); + auto res = cli_.Get("/"); ASSERT_TRUE(res != nullptr); EXPECT_EQ(302, res->status); EXPECT_EQ("/hi", res->get_header_value("Location")); @@ -405,14 +415,14 @@ TEST_F(ServerTest, GetMethod302) TEST_F(ServerTest, GetMethod404) { - auto res = cli_.get("/invalid"); + auto res = cli_.Get("/invalid"); ASSERT_TRUE(res != nullptr); EXPECT_EQ(404, res->status); } TEST_F(ServerTest, HeadMethod200) { - auto res = cli_.head("/hi"); + auto res = cli_.Head("/hi"); ASSERT_TRUE(res != nullptr); EXPECT_EQ(200, res->status); EXPECT_EQ("text/plain", res->get_header_value("Content-Type")); @@ -421,7 +431,7 @@ TEST_F(ServerTest, HeadMethod200) TEST_F(ServerTest, HeadMethod404) { - auto res = cli_.head("/invalid"); + auto res = cli_.Head("/invalid"); ASSERT_TRUE(res != nullptr); EXPECT_EQ(404, res->status); EXPECT_EQ("", res->body); @@ -429,7 +439,7 @@ TEST_F(ServerTest, HeadMethod404) TEST_F(ServerTest, GetMethodPersonJohn) { - auto res = cli_.get("/person/john"); + auto res = cli_.Get("/person/john"); ASSERT_TRUE(res != nullptr); EXPECT_EQ(200, res->status); EXPECT_EQ("text/plain", res->get_header_value("Content-Type")); @@ -438,15 +448,15 @@ TEST_F(ServerTest, GetMethodPersonJohn) TEST_F(ServerTest, PostMethod1) { - auto res = cli_.get("/person/john1"); + auto res = cli_.Get("/person/john1"); ASSERT_TRUE(res != nullptr); ASSERT_EQ(404, res->status); - res = cli_.post("/person", "name=john1¬e=coder", "application/x-www-form-urlencoded"); + res = cli_.Post("/person", "name=john1¬e=coder", "application/x-www-form-urlencoded"); ASSERT_TRUE(res != nullptr); ASSERT_EQ(200, res->status); - res = cli_.get("/person/john1"); + res = cli_.Get("/person/john1"); ASSERT_TRUE(res != nullptr); ASSERT_EQ(200, res->status); ASSERT_EQ("text/plain", res->get_header_value("Content-Type")); @@ -455,7 +465,7 @@ TEST_F(ServerTest, PostMethod1) TEST_F(ServerTest, PostMethod2) { - auto res = cli_.get("/person/john2"); + auto res = cli_.Get("/person/john2"); ASSERT_TRUE(res != nullptr); ASSERT_EQ(404, res->status); @@ -463,11 +473,11 @@ TEST_F(ServerTest, PostMethod2) params.emplace("name", "john2"); params.emplace("note", "coder"); - res = cli_.post("/person", params); + res = cli_.Post("/person", params); ASSERT_TRUE(res != nullptr); ASSERT_EQ(200, res->status); - res = cli_.get("/person/john2"); + res = cli_.Get("/person/john2"); ASSERT_TRUE(res != nullptr); ASSERT_EQ(200, res->status); ASSERT_EQ("text/plain", res->get_header_value("Content-Type")); @@ -476,7 +486,7 @@ TEST_F(ServerTest, PostMethod2) TEST_F(ServerTest, GetMethodDir) { - auto res = cli_.get("/dir/"); + auto res = cli_.Get("/dir/"); ASSERT_TRUE(res != nullptr); EXPECT_EQ(200, res->status); EXPECT_EQ("text/html", res->get_header_value("Content-Type")); @@ -495,7 +505,7 @@ TEST_F(ServerTest, GetMethodDir) TEST_F(ServerTest, GetMethodDirTest) { - auto res = cli_.get("/dir/test.html"); + auto res = cli_.Get("/dir/test.html"); ASSERT_TRUE(res != nullptr); EXPECT_EQ(200, res->status); EXPECT_EQ("text/html", res->get_header_value("Content-Type")); @@ -504,7 +514,7 @@ TEST_F(ServerTest, GetMethodDirTest) TEST_F(ServerTest, GetMethodDirTestWithDoubleDots) { - auto res = cli_.get("/dir/../dir/test.html"); + auto res = cli_.Get("/dir/../dir/test.html"); ASSERT_TRUE(res != nullptr); EXPECT_EQ(200, res->status); EXPECT_EQ("text/html", res->get_header_value("Content-Type")); @@ -513,21 +523,21 @@ TEST_F(ServerTest, GetMethodDirTestWithDoubleDots) TEST_F(ServerTest, GetMethodInvalidPath) { - auto res = cli_.get("/dir/../test.html"); + auto res = cli_.Get("/dir/../test.html"); ASSERT_TRUE(res != nullptr); EXPECT_EQ(404, res->status); } TEST_F(ServerTest, GetMethodOutOfBaseDir) { - auto res = cli_.get("/../www/dir/test.html"); + auto res = cli_.Get("/../www/dir/test.html"); ASSERT_TRUE(res != nullptr); EXPECT_EQ(404, res->status); } TEST_F(ServerTest, GetMethodOutOfBaseDir2) { - auto res = cli_.get("/dir/../../www/dir/test.html"); + auto res = cli_.Get("/dir/../../www/dir/test.html"); ASSERT_TRUE(res != nullptr); EXPECT_EQ(404, res->status); } @@ -540,13 +550,13 @@ TEST_F(ServerTest, InvalidBaseDir) TEST_F(ServerTest, EmptyRequest) { - auto res = cli_.get(""); + auto res = cli_.Get(""); ASSERT_TRUE(res == nullptr); } TEST_F(ServerTest, LongRequest) { - auto res = cli_.get("/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/__ok__"); + auto res = cli_.Get("/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/__ok__"); ASSERT_TRUE(res != nullptr); EXPECT_EQ(404, res->status); @@ -554,7 +564,7 @@ TEST_F(ServerTest, LongRequest) TEST_F(ServerTest, TooLongRequest) { - auto res = cli_.get("/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/__ng___"); + auto res = cli_.Get("/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/TooLongRequest/__ng___"); ASSERT_TRUE(res != nullptr); EXPECT_EQ(404, res->status); @@ -610,28 +620,28 @@ TEST_F(ServerTest, TooLongHeader) TEST_F(ServerTest, PercentEncoding) { - auto res = cli_.get("/e%6edwith%"); + auto res = cli_.Get("/e%6edwith%"); ASSERT_TRUE(res != nullptr); EXPECT_EQ(200, res->status); } TEST_F(ServerTest, PercentEncodingUnicode) { - auto res = cli_.get("/e%u006edwith%"); + auto res = cli_.Get("/e%u006edwith%"); ASSERT_TRUE(res != nullptr); EXPECT_EQ(200, res->status); } TEST_F(ServerTest, InvalidPercentEncoding) { - auto res = cli_.get("/%endwith%"); + auto res = cli_.Get("/%endwith%"); ASSERT_TRUE(res != nullptr); EXPECT_EQ(404, res->status); } TEST_F(ServerTest, InvalidPercentEncodingUnicode) { - auto res = cli_.get("/%uendwith%"); + auto res = cli_.Get("/%uendwith%"); ASSERT_TRUE(res != nullptr); EXPECT_EQ(404, res->status); } @@ -663,7 +673,7 @@ TEST_F(ServerTest, MultipartFormData) TEST_F(ServerTest, CaseInsensitiveHeaderName) { - auto res = cli_.get("/hi"); + auto res = cli_.Get("/hi"); ASSERT_TRUE(res != nullptr); EXPECT_EQ(200, res->status); EXPECT_EQ("text/plain", res->get_header_value("content-type")); @@ -731,7 +741,7 @@ TEST_F(ServerTest, LargeChunkedPost) { TEST_F(ServerTest, GetMethodRemoteAddr) { - auto res = cli_.get("/remote_addr"); + auto res = cli_.Get("/remote_addr"); ASSERT_TRUE(res != nullptr); EXPECT_EQ(200, res->status); EXPECT_EQ("text/plain", res->get_header_value("Content-Type")); @@ -740,18 +750,43 @@ TEST_F(ServerTest, GetMethodRemoteAddr) TEST_F(ServerTest, SlowRequest) { - request_threads_.push_back(std::thread([=]() { auto res = cli_.get("/slow"); })); - request_threads_.push_back(std::thread([=]() { auto res = cli_.get("/slow"); })); - request_threads_.push_back(std::thread([=]() { auto res = cli_.get("/slow"); })); + request_threads_.push_back(std::thread([=]() { auto res = cli_.Get("/slow"); })); + request_threads_.push_back(std::thread([=]() { auto res = cli_.Get("/slow"); })); + request_threads_.push_back(std::thread([=]() { auto res = cli_.Get("/slow"); })); msleep(100); } +TEST_F(ServerTest, Put) +{ + auto res = cli_.Put("/put", "PUT", "text/plain"); + ASSERT_TRUE(res != nullptr); + EXPECT_EQ(200, res->status); + EXPECT_EQ("PUT", res->body); +} + +TEST_F(ServerTest, Delete) +{ + auto res = cli_.Delete("/delete"); + ASSERT_TRUE(res != nullptr); + EXPECT_EQ(200, res->status); + EXPECT_EQ("DELETE", res->body); +} + +TEST_F(ServerTest, Options) +{ + auto res = cli_.Options("*"); + ASSERT_TRUE(res != nullptr); + EXPECT_EQ(200, res->status); + EXPECT_EQ("GET, POST, HEAD, OPTIONS", res->get_header_value("Allow")); + EXPECT_TRUE(res->body.empty()); +} + #ifdef CPPHTTPLIB_ZLIB_SUPPORT TEST_F(ServerTest, Gzip) { Headers headers; headers.emplace("Accept-Encoding", "gzip, deflate"); - auto res = cli_.get("/gzip", headers); + auto res = cli_.Get("/gzip", headers); ASSERT_TRUE(res != nullptr); EXPECT_EQ("gzip", res->get_header_value("Content-Encoding")); @@ -765,7 +800,7 @@ TEST_F(ServerTest, NoGzip) { Headers headers; headers.emplace("Accept-Encoding", "gzip, deflate"); - auto res = cli_.get("/nogzip", headers); + auto res = cli_.Get("/nogzip", headers); ASSERT_TRUE(res != nullptr); EXPECT_EQ(false, res->has_header("Content-Encoding")); @@ -839,7 +874,7 @@ protected: {} virtual void SetUp() { - svr_.get("/hi", [&](const Request& /*req*/, Response& res) { + svr_.Get("/hi", [&](const Request& /*req*/, Response& res) { res.set_content("Hello World!", "text/plain"); }); @@ -869,7 +904,7 @@ protected: TEST_F(ServerTestWithAI_PASSIVE, GetMethod200) { - auto res = cli_.get("/hi"); + auto res = cli_.Get("/hi"); ASSERT_TRUE(res != nullptr); EXPECT_EQ(200, res->status); EXPECT_EQ("text/plain", res->get_header_value("Content-Type")); @@ -914,7 +949,7 @@ TEST_F(ServerUpDownTest, QuickStartStop) TEST(SSLClientTest, ServerNameIndication) { SSLClient cli("httpbin.org", 443); - auto res = cli.get("/get"); + auto res = cli.Get("/get"); ASSERT_TRUE(res != nullptr); ASSERT_EQ(200, res->status); }