Skip to content

Commit

Permalink
fix: Make content_length optional
Browse files Browse the repository at this point in the history
To make it possible to distinguish whether the response has no content
or contains an empty content, wraps `content_length` with `Option`.
Without having 'Content-Length: 0' for an empty content, a client may
wait for the server to close the connection or for a timeout to occur.

Signed-off-by: Takahiro Itazuri <itazur@amazon.com>
  • Loading branch information
zulinx86 committed Feb 21, 2024
1 parent e75dfa1 commit c295b53
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 5 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

- Mark `HttpServer::new_from_fd` as `unsafe` as the correctness of the unsafe code
in this method relies on an invariant the caller has to uphold
- Set `Content-Length: 0` when setting an empty body in the response.

# v0.1.0

Expand Down
26 changes: 21 additions & 5 deletions src/response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ impl StatusLine {
/// The content type can be updated with a call to `set_content_type`.
#[derive(Debug, PartialEq, Eq)]
pub struct ResponseHeaders {
content_length: i32,
content_length: Option<i32>,
content_type: MediaType,
deprecation: bool,
server: String,
Expand Down Expand Up @@ -151,15 +151,15 @@ impl ResponseHeaders {
self.write_allow_header(buf)?;
self.write_deprecation_header(buf)?;

if self.content_length != 0 {
if let Some(content_length) = self.content_length {
buf.write_all(Header::ContentType.raw())?;
buf.write_all(&[COLON, SP])?;
buf.write_all(self.content_type.as_str().as_bytes())?;
buf.write_all(&[CR, LF])?;

buf.write_all(Header::ContentLength.raw())?;
buf.write_all(&[COLON, SP])?;
buf.write_all(self.content_length.to_string().as_bytes())?;
buf.write_all(content_length.to_string().as_bytes())?;
buf.write_all(&[CR, LF])?;

if self.accept_encoding {
Expand All @@ -175,7 +175,7 @@ impl ResponseHeaders {

// Sets the content length to be written in the HTTP response.
fn set_content_length(&mut self, content_length: i32) {
self.content_length = content_length;
self.content_length = Some(content_length);
}

/// Sets the HTTP response header server.
Expand Down Expand Up @@ -296,7 +296,7 @@ impl Response {

/// Returns the Content Length of the response.
pub fn content_length(&self) -> i32 {
self.headers.content_length
self.headers.content_length.unwrap_or(0)
}

/// Returns the Content Type of the response.
Expand Down Expand Up @@ -480,4 +480,20 @@ mod tests {
let another_response = Response::new(Version::Http10, StatusCode::BadRequest);
assert_ne!(response, another_response);
}

#[test]
fn test_content_length() {
let mut response = Response::new(Version::Http10, StatusCode::OK);

// When not calling `set_body()`, the content_length must be 0 and the body must be None.
assert_eq!(response.content_length(), 0);
assert_eq!(response.body(), None);

// When calling `set_body()` with an empty content, the content_length must also be 0
// and the body is an empty content.
let body = Body::new("");
response.set_body(body.clone());
assert_eq!(response.content_length(), 0);
assert_eq!(response.body(), Some(body));
}
}

0 comments on commit c295b53

Please sign in to comment.