From b342c38f08972fe8be4ef9844e30f1e7a121bbc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Oliveira?= Date: Tue, 7 May 2019 20:53:25 +0100 Subject: [PATCH] fix(server): skip automatic Content-Length header for HTTP 304 responses Closes #1797 --- src/proto/h1/role.rs | 17 ++++++++++------ tests/server.rs | 46 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 56 insertions(+), 7 deletions(-) diff --git a/src/proto/h1/role.rs b/src/proto/h1/role.rs index 6569384884..937b23d99e 100644 --- a/src/proto/h1/role.rs +++ b/src/proto/h1/role.rs @@ -476,14 +476,20 @@ impl Http1Transaction for Server { }, None | Some(BodyLength::Known(0)) => { - extend(dst, b"content-length: 0\r\n"); + if msg.head.subject != StatusCode::NOT_MODIFIED { + extend(dst, b"content-length: 0\r\n"); + } Encoder::length(0) }, Some(BodyLength::Known(len)) => { - extend(dst, b"content-length: "); - let _ = ::itoa::write(&mut dst, len); - extend(dst, b"\r\n"); - Encoder::length(len) + if msg.head.subject == StatusCode::NOT_MODIFIED { + Encoder::length(0) + } else { + extend(dst, b"content-length: "); + let _ = ::itoa::write(&mut dst, len); + extend(dst, b"\r\n"); + Encoder::length(len) + } }, }; } @@ -1583,4 +1589,3 @@ mod tests { }) } } - diff --git a/tests/server.rs b/tests/server.rs index 8baee02196..de356435cd 100644 --- a/tests/server.rs +++ b/tests/server.rs @@ -1687,6 +1687,51 @@ fn http2_service_poll_ready_error_sends_goaway() { assert_eq!(h2_err.reason(), Some(h2::Reason::INADEQUATE_SECURITY)); } +#[test] +fn skips_content_length_for_304_responses() { + let server = serve(); + server.reply() + + .status(hyper::StatusCode::NOT_MODIFIED) + .body("foo"); + let mut req = connect(server.addr()); + req.write_all(b"\ + GET / 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:")); +} + +#[test] +fn skips_content_length_and_body_for_304_responses() { + let server = serve(); + server.reply() + + .status(hyper::StatusCode::NOT_MODIFIED) + .body("foo"); + let mut req = connect(server.addr()); + req.write_all(b"\ + GET / 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:")); + let mut lines = response.lines(); + assert_eq!(lines.next(), Some("HTTP/1.1 304 Not Modified")); + + let mut lines = lines.skip_while(|line| !line.is_empty()); + assert_eq!(lines.next(), Some("")); + assert_eq!(lines.next(), None); +} // ------------------------------------------------- // the Server that is used to run all the tests with // ------------------------------------------------- @@ -2058,4 +2103,3 @@ impl Drop for Dropped { self.0.store(true, Ordering::SeqCst); } } -