diff --git a/src/proto/h1/role.rs b/src/proto/h1/role.rs index 958340775a..cad25d1ab9 100644 --- a/src/proto/h1/role.rs +++ b/src/proto/h1/role.rs @@ -1288,6 +1288,13 @@ impl Client { body } else { head.headers.remove(header::TRANSFER_ENCODING); + // If we know there's body coming, set a content-length. + // But only if the method normally has a body. + // GET, HEAD, and CONNECT are assumed empty. + if !is_method_assumed_empty(&head.subject.0) { + head.headers + .insert(header::CONTENT_LENGTH, HeaderValue::from_static("0")); + } return Encoder::length(0); }; @@ -1361,12 +1368,11 @@ impl Client { // So instead of sending a "chunked" body with a 0-chunk, // assume no body here. If you *must* send a body, // set the headers explicitly. - match head.subject.0 { - Method::GET | Method::HEAD | Method::CONNECT => Some(Encoder::length(0)), - _ => { - te.insert(HeaderValue::from_static("chunked")); - Some(Encoder::chunked()) - } + if is_method_assumed_empty(&head.subject.0) { + Some(Encoder::length(0)) + } else { + te.insert(HeaderValue::from_static("chunked")); + Some(Encoder::chunked()) } } else { None @@ -1468,6 +1474,11 @@ impl Client { } } +#[cfg(feature = "client")] +fn is_method_assumed_empty(method: &Method) -> bool { + matches!(method, &Method::GET | &Method::HEAD | &Method::CONNECT) +} + #[cfg(feature = "client")] fn set_content_length(headers: &mut HeaderMap, len: u64) -> Encoder { // At this point, there should not be a valid Content-Length diff --git a/tests/client.rs b/tests/client.rs index 43e1f08acb..73d080f3f7 100644 --- a/tests/client.rs +++ b/tests/client.rs @@ -888,6 +888,30 @@ test! { body: None, } +test! { + name: client_post_empty_auto_length, + + server: + expected: "\ + POST /empty HTTP/1.1\r\n\ + host: {addr}\r\n\ + content-length: 0\r\n\ + \r\n\ + ", + reply: REPLY_OK, + + client: + request: { + method: POST, + url: "http://{addr}/empty", + headers: {}, + }, + response: + status: OK, + headers: {}, + body: None, +} + test! { name: client_head_ignores_body,