Skip to content

Commit

Permalink
Strip body and content-length on 204, body on 304.
Browse files Browse the repository at this point in the history
This works-around an issue where hyper incorrectly removes the body on
204 responses without removing the content-length or setting it to zero.

Resolves #2821.
  • Loading branch information
SergioBenitez committed Aug 23, 2024
1 parent d332339 commit 9496b70
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 3 deletions.
11 changes: 8 additions & 3 deletions core/lib/src/lifecycle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,12 +134,17 @@ impl Rocket<Orbit> {
// 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());
}

Expand Down
8 changes: 8 additions & 0 deletions core/lib/src/response/body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<T>(body: T, preset_size: Option<usize>) -> Self
where T: AsyncReadSeek + Send + 'r
{
Expand Down
1 change: 1 addition & 0 deletions testbench/src/servers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ pub mod mtls;
pub mod sni_resolver;
pub mod tracing;
pub mod tls;
pub mod no_content;
30 changes: 30 additions & 0 deletions testbench/src/servers/no_content.rs
Original file line number Diff line number Diff line change
@@ -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("/<code>")]
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);

0 comments on commit 9496b70

Please sign in to comment.