codegen: auto-register HEAD guard for #[get] routes

Per RFC 7231 Section 4.3.2, a server that supports GET must also
support HEAD. The #[get] macro now implicitly registers a HEAD
guard so that HEAD requests are handled without requiring users
to write #[route("/path", method="GET", method="HEAD")].

Fixes #2702
This commit is contained in:
Varun Chawla 2026-02-22 20:16:17 -08:00
parent 96a4964c1b
commit 218fe0a663
No known key found for this signature in database
2 changed files with 26 additions and 0 deletions

View File

@ -240,6 +240,12 @@ impl Args {
let is_route_macro = method.is_none(); let is_route_macro = method.is_none();
if let Some(method) = method { if let Some(method) = method {
// Per RFC 7231 Section 4.3.2, a server that supports GET must also
// support HEAD. Automatically register a HEAD guard alongside GET
// so that `#[get(...)]` handlers respond to HEAD requests.
if method == MethodType::Get {
methods.insert(MethodTypeExt::Standard(MethodType::Head));
}
methods.insert(MethodTypeExt::Standard(method)); methods.insert(MethodTypeExt::Standard(method));
} }

View File

@ -384,3 +384,23 @@ async fn test_wrap() {
let body = String::from_utf8(body.to_vec()).unwrap(); let body = String::from_utf8(body.to_vec()).unwrap();
assert!(body.contains("wrong number of parameters")); assert!(body.contains("wrong number of parameters"));
} }
#[get("/head-from-get")]
async fn get_head_implicit() -> impl Responder {
HttpResponse::Ok().body("hello")
}
#[actix_web::test]
async fn test_get_implies_head() {
let srv = actix_test::start(|| App::new().service(get_head_implicit));
// GET should work as usual
let request = srv.request(http::Method::GET, srv.url("/head-from-get"));
let response = request.send().await.unwrap();
assert_eq!(response.status(), StatusCode::OK);
// HEAD should also work on a #[get] endpoint per RFC 7231
let request = srv.request(http::Method::HEAD, srv.url("/head-from-get"));
let response = request.send().await.unwrap();
assert_eq!(response.status(), StatusCode::OK);
}