diff --git a/include/crow/routing.h b/include/crow/routing.h index e8465634d..8ad887bc5 100644 --- a/include/crow/routing.h +++ b/include/crow/routing.h @@ -1538,7 +1538,10 @@ namespace crow return; else if (req.method == HTTPMethod::Head) { - method_actual = HTTPMethod::Get; + // support HEAD requests using GET if not defined as method for the requested URL + if (!std::get<0>(per_methods_[static_cast(HTTPMethod::Head)].trie.find(req.url))) + method_actual = HTTPMethod::Get; + res.skip_body = true; } else if (req.method == HTTPMethod::Options) @@ -1549,6 +1552,9 @@ namespace crow { for (int i = 0; i < static_cast(HTTPMethod::InternalMethodCount); i++) { + if (static_cast(HTTPMethod::Head) == i) + continue; // HEAD is always allowed + if (!per_methods_[i].trie.is_empty()) { allow += method_name(static_cast(i)) + ", "; @@ -1562,14 +1568,20 @@ namespace crow } else { + bool rules_matched = false; for (int i = 0; i < static_cast(HTTPMethod::InternalMethodCount); i++) { if (std::get<0>(per_methods_[i].trie.find(req.url))) { + rules_matched = true; + + if (static_cast(HTTPMethod::Head) == i) + continue; // HEAD is always allowed + allow += method_name(static_cast(i)) + ", "; } } - if (allow != "OPTIONS, HEAD, ") + if (rules_matched) { allow = allow.substr(0, allow.size() - 2); res = response(204); diff --git a/tests/unittest.cpp b/tests/unittest.cpp index 1e8353e4c..b366804ae 100644 --- a/tests/unittest.cpp +++ b/tests/unittest.cpp @@ -307,6 +307,10 @@ TEST_CASE("http_method") return "1"; }); + CROW_ROUTE(app, "/head_only") + .methods("HEAD"_method)([](const request& /*req*/) { + return response{202}; + }); CROW_ROUTE(app, "/get_only") .methods("GET"_method)([](const request& /*req*/) { return "get"; @@ -352,6 +356,18 @@ TEST_CASE("http_method") CHECK("1" == res.body); } + { + request req; + response res; + + req.url = "/head_only"; + req.method = "HEAD"_method; + app.handle(req, res); + + CHECK(202 == res.code); + CHECK("" == res.body); + } + { request req; response res; @@ -452,6 +468,18 @@ TEST_CASE("http_method") CHECK(204 == res.code); CHECK("OPTIONS, HEAD, GET, POST, PATCH, PURGE" == res.get_header_value("Allow")); } + + { + request req; + response res; + + req.url = "/head_only"; + req.method = "OPTIONS"_method; + app.handle(req, res); + + CHECK(204 == res.code); + CHECK("OPTIONS, HEAD" == res.get_header_value("Allow")); + } } // http_method TEST_CASE("server_handling_error_request")