From 67b73138f110979f3c77ef7b56588f018837e592 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jannes=20=28=E6=80=9D=E6=98=8E=29?= Date: Wed, 18 May 2022 19:49:58 +0200 Subject: [PATCH] fix(server): don't add implicit content-length to HEAD responses (#2836) HEAD responses should not have content-length implicitly set by hyper. Co-authored-by: Jannes Timm --- src/proto/h1/role.rs | 15 +++++++++++---- tests/server.rs | 20 ++++++++++++++++++++ 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/src/proto/h1/role.rs b/src/proto/h1/role.rs index a3ff075476..a5df16b0b3 100644 --- a/src/proto/h1/role.rs +++ b/src/proto/h1/role.rs @@ -1,8 +1,6 @@ use std::fmt::{self, Write}; use std::mem::MaybeUninit; -#[cfg(all(feature = "server", feature = "runtime"))] -use tokio::time::Instant; #[cfg(any(test, feature = "server", feature = "ffi"))] use bytes::Bytes; use bytes::BytesMut; @@ -10,6 +8,8 @@ use bytes::BytesMut; use http::header::ValueIter; use http::header::{self, Entry, HeaderName, HeaderValue}; use http::{HeaderMap, Method, StatusCode, Version}; +#[cfg(all(feature = "server", feature = "runtime"))] +use tokio::time::Instant; use tracing::{debug, error, trace, trace_span, warn}; use crate::body::DecodedLength; @@ -487,6 +487,10 @@ impl Server { } } + fn can_have_implicit_zero_content_length(method: &Option, status: StatusCode) -> bool { + Server::can_have_content_length(method, status) && method != &Some(Method::HEAD) + } + fn encode_headers_with_lower_case( msg: Encode<'_, StatusCode>, dst: &mut Vec, @@ -839,7 +843,10 @@ impl Server { } } None | Some(BodyLength::Known(0)) => { - if Server::can_have_content_length(msg.req_method, msg.head.subject) { + if Server::can_have_implicit_zero_content_length( + msg.req_method, + msg.head.subject, + ) { header_name_writer.write_full_header_line( dst, "content-length: 0\r\n", @@ -1033,7 +1040,7 @@ impl Http1Transaction for Client { } #[cfg(feature = "ffi")] - if let Some(ref mut header_order) = header_order { + if let Some(ref mut header_order) = header_order { header_order.append(&name); } diff --git a/tests/server.rs b/tests/server.rs index 82491ec408..3362b51855 100644 --- a/tests/server.rs +++ b/tests/server.rs @@ -2421,6 +2421,26 @@ fn skips_content_length_and_body_for_304_responses() { assert_eq!(lines.next(), None); } +#[test] +fn no_implicit_zero_content_length_for_head_responses() { + let server = serve(); + server.reply().status(hyper::StatusCode::OK).body([]); + let mut req = connect(server.addr()); + req.write_all( + b"\ + HEAD / HTTP/1.1\r\n\ + Host: example.domain\r\n\ + Connection: close\r\n\ + \r\n\ + ", + ) + .unwrap(); + + let mut response = String::new(); + req.read_to_string(&mut response).unwrap(); + assert!(!response.contains("content-length:")); +} + #[tokio::test] async fn http2_keep_alive_detects_unresponsive_client() { let _ = pretty_env_logger::try_init();