From 5a9338d71a68a0accb6ca217ec7a4aa470ed9510 Mon Sep 17 00:00:00 2001 From: Rasmus Melchior Jacobsen Date: Tue, 21 May 2024 14:15:53 +0200 Subject: [PATCH] Handle no-content status code 204 --- src/response/mod.rs | 45 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/src/response/mod.rs b/src/response/mod.rs index 8febc9c..79250e6 100644 --- a/src/response/mod.rs +++ b/src/response/mod.rs @@ -81,7 +81,7 @@ where let mut response = httparse::Response::new(&mut headers); response.parse(&header_buf[..header_len]).unwrap(); - let status = response.code.unwrap().into(); + let status: StatusCode = response.code.unwrap().into(); let mut content_type = None; let mut content_length = None; let mut transfer_encoding = Vec::new(); @@ -106,6 +106,16 @@ where } } + if status.is_informational() || status == Status::NoContent { + // According to https://datatracker.ietf.org/doc/html/rfc7230#section-3.3.2 + // A server MUST NOT send a Content-Length header field in any response + // with a status code of 1xx (Informational) or 204 (No Content) + if content_length.unwrap_or_default() != 0 { + return Err(Error::Codec); + } + content_length = Some(0); + } + // The number of bytes that we have read into the body part of the response let raw_body_read = pos - header_len; @@ -533,6 +543,39 @@ mod tests { Error, TryBufRead, }; + #[tokio::test] + async fn can_read_no_content() { + let mut conn = FakeSingleReadConnection::new(b"HTTP/1.1 204 No Content\r\n\r\n"); + let mut response_buf = [0; 200]; + let response = Response::read(&mut conn, Method::POST, &mut response_buf) + .await + .unwrap(); + + assert_eq!(b"", response.body().read_to_end().await.unwrap()); + assert!(conn.is_exhausted()); + } + + #[tokio::test] + async fn can_read_no_content_with_zero_content_length() { + let mut conn = FakeSingleReadConnection::new(b"HTTP/1.1 204 No Content\r\nContent-Length: 0\r\n\r\n"); + let mut response_buf = [0; 200]; + let response = Response::read(&mut conn, Method::POST, &mut response_buf) + .await + .unwrap(); + + assert_eq!(b"", response.body().read_to_end().await.unwrap()); + assert!(conn.is_exhausted()); + } + + #[tokio::test] + async fn cannot_read_no_content_with_nonzero_content_length() { + let mut conn = FakeSingleReadConnection::new(b"HTTP/1.1 204 No Content\r\nContent-Length: 5\r\n\r\nHELLO"); + let mut response_buf = [0; 200]; + let response = Response::read(&mut conn, Method::POST, &mut response_buf).await; + + assert!(matches!(response, Err(Error::Codec))); + } + #[tokio::test] async fn can_read_with_content_length_with_same_buffer() { let mut conn = FakeSingleReadConnection::new(b"HTTP/1.1 200 OK\r\nContent-Length: 11\r\n\r\nHELLO WORLD");