diff --git a/amalgamate/crow_all.h b/amalgamate/crow_all.h index a567b5a4b..43a3af4fd 100644 --- a/amalgamate/crow_all.h +++ b/amalgamate/crow_all.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 : @@ -6113,8 +6115,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 @@ -6234,6 +6241,7 @@ namespace crow self_t& methods(HTTPMethod method) { methods_ = 1<<(int)method; + return *this; } template @@ -6241,6 +6249,7 @@ namespace crow { methods(args_method...); methods_ |= 1<<(int)method; + return *this; } void validate() @@ -6344,7 +6353,6 @@ namespace crow std::string rule_; std::string name_; - uint32_t methods_{1<<(int)HTTPMethod::GET}; template struct call_pair @@ -6725,7 +6733,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: " << req.url << " 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 ca881928c..87d492b43 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 @@ -638,7 +644,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: " << req.url << " 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 87acb525a..1a157429e 100644 --- a/tests/unittest.cpp +++ b/tests/unittest.cpp @@ -250,6 +250,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]; @@ -283,8 +356,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); @@ -298,7 +371,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));