Skip to content

Commit 9496b70

Browse files
committed
Strip body and content-length on 204, body on 304.
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 rwf2#2821.
1 parent d332339 commit 9496b70

File tree

4 files changed

+47
-3
lines changed

4 files changed

+47
-3
lines changed

core/lib/src/lifecycle.rs

+8-3
Original file line numberDiff line numberDiff line change
@@ -134,12 +134,17 @@ impl Rocket<Orbit> {
134134
// Run the response fairings.
135135
self.fairings.handle_response(request, &mut response).await;
136136

137-
// Strip the body if this is a `HEAD` request.
138-
if was_head_request {
137+
// Strip the body if this is a `HEAD` request or a 304 response.
138+
if was_head_request || response.status() == Status::NotModified {
139139
response.strip_body();
140140
}
141141

142-
if let Some(size) = response.body_mut().size().await {
142+
// If the response status is 204, strip the body and its size (no
143+
// content-length header). Otherwise, check if the body is sized and use
144+
// that size to set the content-length headr appropriately.
145+
if response.status() == Status::NoContent {
146+
*response.body_mut() = crate::response::Body::unsized_none();
147+
} else if let Some(size) = response.body_mut().size().await {
143148
response.set_raw_header("Content-Length", size.to_string());
144149
}
145150

core/lib/src/response/body.rs

+8
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,14 @@ impl<'r> Body<'r> {
107107
/// The present value is `4096`.
108108
pub const DEFAULT_MAX_CHUNK: usize = 4096;
109109

110+
pub(crate) fn unsized_none() -> Self {
111+
Body {
112+
size: None,
113+
inner: Inner::None,
114+
max_chunk: Body::DEFAULT_MAX_CHUNK,
115+
}
116+
}
117+
110118
pub(crate) fn with_sized<T>(body: T, preset_size: Option<usize>) -> Self
111119
where T: AsyncReadSeek + Send + 'r
112120
{

testbench/src/servers/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ pub mod mtls;
77
pub mod sni_resolver;
88
pub mod tracing;
99
pub mod tls;
10+
pub mod no_content;

testbench/src/servers/no_content.rs

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
//! Ensure that responses with a status of 204 or 304 do not have a body, and
2+
//! for the former, do not have a Content-Length header.
3+
4+
use crate::prelude::*;
5+
6+
use rocket::http::Status;
7+
8+
#[get("/<code>")]
9+
fn status(code: u16) -> (Status, &'static [u8]) {
10+
(Status::new(code), &[1, 2, 3, 4])
11+
}
12+
13+
pub fn test_no_content() -> Result<()> {
14+
let server = spawn!(Rocket::default().mount("/", routes![status]))?;
15+
16+
let client = Client::default();
17+
let response = client.get(&server, "/204")?.send()?;
18+
assert_eq!(response.status(), 204);
19+
assert!(response.headers().get("Content-Length").is_none());
20+
assert!(response.bytes()?.is_empty());
21+
22+
let response = client.get(&server, "/304")?.send()?;
23+
assert_eq!(response.status(), 304);
24+
assert_eq!(response.headers().get("Content-Length").unwrap(), "4");
25+
assert!(response.bytes()?.is_empty());
26+
27+
Ok(())
28+
}
29+
30+
register!(test_no_content);

0 commit comments

Comments
 (0)