diff --git a/core/lib/src/lifecycle.rs b/core/lib/src/lifecycle.rs index 6f51c959..cf76e3be 100644 --- a/core/lib/src/lifecycle.rs +++ b/core/lib/src/lifecycle.rs @@ -134,12 +134,17 @@ impl Rocket { // Run the response fairings. self.fairings.handle_response(request, &mut response).await; - // Strip the body if this is a `HEAD` request. - if was_head_request { + // Strip the body if this is a `HEAD` request or a 304 response. + if was_head_request || response.status() == Status::NotModified { response.strip_body(); } - if let Some(size) = response.body_mut().size().await { + // If the response status is 204, strip the body and its size (no + // content-length header). Otherwise, check if the body is sized and use + // that size to set the content-length headr appropriately. + if response.status() == Status::NoContent { + *response.body_mut() = crate::response::Body::unsized_none(); + } else if let Some(size) = response.body_mut().size().await { response.set_raw_header("Content-Length", size.to_string()); } diff --git a/core/lib/src/response/body.rs b/core/lib/src/response/body.rs index f0b2ac9b..a50ef446 100644 --- a/core/lib/src/response/body.rs +++ b/core/lib/src/response/body.rs @@ -107,6 +107,14 @@ impl<'r> Body<'r> { /// The present value is `4096`. pub const DEFAULT_MAX_CHUNK: usize = 4096; + pub(crate) fn unsized_none() -> Self { + Body { + size: None, + inner: Inner::None, + max_chunk: Body::DEFAULT_MAX_CHUNK, + } + } + pub(crate) fn with_sized(body: T, preset_size: Option) -> Self where T: AsyncReadSeek + Send + 'r { diff --git a/testbench/src/servers/mod.rs b/testbench/src/servers/mod.rs index d05aa00c..0a9c615f 100644 --- a/testbench/src/servers/mod.rs +++ b/testbench/src/servers/mod.rs @@ -7,3 +7,4 @@ pub mod mtls; pub mod sni_resolver; pub mod tracing; pub mod tls; +pub mod no_content; diff --git a/testbench/src/servers/no_content.rs b/testbench/src/servers/no_content.rs new file mode 100644 index 00000000..bef08681 --- /dev/null +++ b/testbench/src/servers/no_content.rs @@ -0,0 +1,30 @@ +//! Ensure that responses with a status of 204 or 304 do not have a body, and +//! for the former, do not have a Content-Length header. + +use crate::prelude::*; + +use rocket::http::Status; + +#[get("/")] +fn status(code: u16) -> (Status, &'static [u8]) { + (Status::new(code), &[1, 2, 3, 4]) +} + +pub fn test_no_content() -> Result<()> { + let server = spawn!(Rocket::default().mount("/", routes![status]))?; + + let client = Client::default(); + let response = client.get(&server, "/204")?.send()?; + assert_eq!(response.status(), 204); + assert!(response.headers().get("Content-Length").is_none()); + assert!(response.bytes()?.is_empty()); + + let response = client.get(&server, "/304")?.send()?; + assert_eq!(response.status(), 304); + assert_eq!(response.headers().get("Content-Length").unwrap(), "4"); + assert!(response.bytes()?.is_empty()); + + Ok(()) +} + +register!(test_no_content);