From a5fab23f70e6e33c633ba4b646a41d0851169ad1 Mon Sep 17 00:00:00 2001 From: ipknHama Date: Tue, 7 Oct 2014 21:51:24 +0900 Subject: [PATCH] HTTP GET/POST method distinguish --- amalgamate/crow_all.h | 24 ++++++++++-- examples/example_chat.cpp | 1 + include/routing.h | 20 ++++++++-- include/utility.h | 4 +- tests/unittest.cpp | 78 +++++++++++++++++++++++++++++++++++++-- 5 files changed, 116 insertions(+), 11 deletions(-) diff --git a/amalgamate/crow_all.h b/amalgamate/crow_all.h index d73276566..2962e7c63 100644 --- a/amalgamate/crow_all.h +++ b/amalgamate/crow_all.h @@ -5014,7 +5014,9 @@ namespace crow constexpr bool is_equ_p(const char* a, const char* b, unsigned n) { return - *a == 0 || *b == 0 + *a == 0 && *b == 0 && n == 0 + ? true : + (*a == 0 || *b == 0) ? false : n == 0 ? true : @@ -5908,8 +5910,13 @@ namespace crow virtual void handle(const request&, response&, const routing_params&) = 0; - protected: + uint32_t methods() + { + return methods_; + } + protected: + uint32_t methods_{1<<(int)HTTPMethod::GET}; }; template @@ -6029,6 +6036,7 @@ namespace crow self_t& methods(HTTPMethod method) { methods_ = 1<<(int)method; + return *this; } template @@ -6036,6 +6044,7 @@ namespace crow { methods(args_method...); methods_ |= 1<<(int)method; + return *this; } void validate() @@ -6139,7 +6148,6 @@ namespace crow std::string rule_; std::string name_; - uint32_t methods_{1<<(int)HTTPMethod::GET}; template struct call_pair @@ -6523,7 +6531,15 @@ public: if (rule_index >= rules_.size()) throw std::runtime_error("Trie internal structure corrupted!"); - CROW_LOG_DEBUG << "Matched rule '" << ((TaggedRule<>*)rules_[rule_index].get())->rule_ << "'"; + if ((rules_[rule_index]->methods() & (1<<(uint32_t)req.method)) == 0) + { + CROW_LOG_DEBUG << "Rule found but method mismatch: " << editedUrl << " with " << method_name(req.method) << "(" << (uint32_t)req.method << ") / " << rules_[rule_index]->methods(); + res = response(404); + res.end(); + return; + } + + CROW_LOG_DEBUG << "Matched rule '" << ((TaggedRule<>*)rules_[rule_index].get())->rule_ << "' " << (uint32_t)req.method << " / " << rules_[rule_index]->methods(); rules_[rule_index]->handle(req, res, found.second); } diff --git a/examples/example_chat.cpp b/examples/example_chat.cpp index 31f16c52e..aa7cc9670 100644 --- a/examples/example_chat.cpp +++ b/examples/example_chat.cpp @@ -79,6 +79,7 @@ int main() }); CROW_ROUTE(app, "/send") + .methods("GET"_method, "POST"_method) ([](const crow::request& req) { CROW_LOG_INFO << "msg from client: " << req.body; diff --git a/include/routing.h b/include/routing.h index d81426619..e62cbce6a 100644 --- a/include/routing.h +++ b/include/routing.h @@ -26,8 +26,13 @@ namespace crow virtual void handle(const request&, response&, const routing_params&) = 0; - protected: + uint32_t methods() + { + return methods_; + } + protected: + uint32_t methods_{1<<(int)HTTPMethod::GET}; }; template @@ -147,6 +152,7 @@ namespace crow self_t& methods(HTTPMethod method) { methods_ = 1<<(int)method; + return *this; } template @@ -154,6 +160,7 @@ namespace crow { methods(args_method...); methods_ |= 1<<(int)method; + return *this; } void validate() @@ -257,7 +264,6 @@ namespace crow std::string rule_; std::string name_; - uint32_t methods_{1<<(int)HTTPMethod::GET}; template struct call_pair @@ -641,7 +647,15 @@ public: if (rule_index >= rules_.size()) throw std::runtime_error("Trie internal structure corrupted!"); - CROW_LOG_DEBUG << "Matched rule '" << ((TaggedRule<>*)rules_[rule_index].get())->rule_ << "'"; + if ((rules_[rule_index]->methods() & (1<<(uint32_t)req.method)) == 0) + { + CROW_LOG_DEBUG << "Rule found but method mismatch: " << editedUrl << " with " << method_name(req.method) << "(" << (uint32_t)req.method << ") / " << rules_[rule_index]->methods(); + res = response(404); + res.end(); + return; + } + + CROW_LOG_DEBUG << "Matched rule '" << ((TaggedRule<>*)rules_[rule_index].get())->rule_ << "' " << (uint32_t)req.method << " / " << rules_[rule_index]->methods(); rules_[rule_index]->handle(req, res, found.second); } diff --git a/include/utility.h b/include/utility.h index b2e61f1dd..c910eb2a2 100644 --- a/include/utility.h +++ b/include/utility.h @@ -67,7 +67,9 @@ namespace crow constexpr bool is_equ_p(const char* a, const char* b, unsigned n) { return - *a == 0 || *b == 0 + *a == 0 && *b == 0 && n == 0 + ? true : + (*a == 0 || *b == 0) ? false : n == 0 ? true : diff --git a/tests/unittest.cpp b/tests/unittest.cpp index 818032fb5..dc04a5fcd 100644 --- a/tests/unittest.cpp +++ b/tests/unittest.cpp @@ -249,6 +249,79 @@ TEST(handler_with_response) }); } +TEST(http_method) +{ + SimpleApp app; + + CROW_ROUTE(app, "/") + .methods("POST"_method, "GET"_method) + ([](const request& req){ + if (req.method == "GET"_method) + return "2"; + else + return "1"; + }); + + CROW_ROUTE(app, "/get_only") + .methods("GET"_method) + ([](const request& req){ + return "get"; + }); + CROW_ROUTE(app, "/post_only") + .methods("POST"_method) + ([](const request& req){ + return "post"; + }); + + + // cannot have multiple handlers for the same url + //CROW_ROUTE(app, "/") + //.methods("GET"_method) + //([]{ return "2"; }); + + { + request req; + response res; + + req.url = "/"; + app.handle(req, res); + + ASSERT_EQUAL("2", res.body); + } + { + request req; + response res; + + req.url = "/"; + req.method = "POST"_method; + app.handle(req, res); + + ASSERT_EQUAL("1", res.body); + } + + { + request req; + response res; + + req.url = "/get_only"; + app.handle(req, res); + + ASSERT_EQUAL("get", res.body); + } + + { + request req; + response res; + + req.url = "/get_only"; + req.method = "POST"_method; + app.handle(req, res); + + ASSERT_NOTEQUAL("get", res.body); + } + +} + TEST(server_handling_error_request) { static char buf[2048]; @@ -282,8 +355,8 @@ TEST(multi_server) { static char buf[2048]; SimpleApp app1, app2; - CROW_ROUTE(app1, "/")([]{return "A";}); - CROW_ROUTE(app2, "/")([]{return "B";}); + CROW_ROUTE(app1, "/").methods("GET"_method, "POST"_method)([]{return "A";}); + CROW_ROUTE(app2, "/").methods("GET"_method, "POST"_method)([]{return "B";}); Server server1(&app1, 45451); Server server2(&app2, 45452); @@ -297,7 +370,6 @@ TEST(multi_server) asio::ip::tcp::socket c(is); c.connect(asio::ip::tcp::endpoint(asio::ip::address::from_string("127.0.0.1"), 45451)); - c.send(asio::buffer(sendmsg)); size_t recved = c.receive(asio::buffer(buf, 2048));