diff --git a/CHANGES.md b/CHANGES.md index d1d838f43..1a3260286 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -12,6 +12,8 @@ * Ignored the `If-Modified-Since` if `If-None-Match` is specified. #680 +* Do not remove `Content-Length` on `Body::Empty` and insert zero value if it is missing for `POST` and `PUT` methods. + ## [0.7.18] - 2019-01-10 ### Added diff --git a/src/client/writer.rs b/src/client/writer.rs index 321753bbf..4091ed212 100644 --- a/src/client/writer.rs +++ b/src/client/writer.rs @@ -16,9 +16,9 @@ use flate2::write::{GzEncoder, ZlibEncoder}; use flate2::Compression; use futures::{Async, Poll}; use http::header::{ - HeaderValue, CONNECTION, CONTENT_ENCODING, CONTENT_LENGTH, DATE, TRANSFER_ENCODING, + self, HeaderValue, CONNECTION, CONTENT_ENCODING, CONTENT_LENGTH, DATE, TRANSFER_ENCODING, }; -use http::{HttpTryFrom, Version}; +use http::{Method, HttpTryFrom, Version}; use time::{self, Duration}; use tokio_io::AsyncWrite; @@ -223,7 +223,19 @@ fn content_encoder(buf: BytesMut, req: &mut ClientRequest) -> Output { let transfer = match body { Body::Empty => { - req.headers_mut().remove(CONTENT_LENGTH); + match req.method() { + //Insert zero content-length only if user hasn't added it. + //We don't really need it for other methods as they are not supposed to carry payload + &Method::POST | &Method::PUT | &Method::PATCH => { + req.headers_mut() + .entry(CONTENT_LENGTH) + .expect("CONTENT_LENGTH to be valid header name") + .or_insert(header::HeaderValue::from_static("0")); + }, + _ => { + req.headers_mut().remove(CONTENT_LENGTH); + } + } return Output::Empty(buf); } Body::Binary(ref mut bytes) => { @@ -410,3 +422,76 @@ impl CachedDate { self.next_update.nsec = 0; } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_content_encoder_empty_body() { + let mut req = ClientRequest::post("http://google.com").finish().expect("Create request"); + + let result = content_encoder(BytesMut::new(), &mut req); + + match result { + Output::Empty(buf) => { + assert_eq!(buf.len(), 0); + let content_len = req.headers().get(CONTENT_LENGTH).expect("To set Content-Length for empty POST"); + assert_eq!(content_len, "0"); + }, + _ => panic!("Unexpected result, should be Output::Empty"), + } + + req.set_method(Method::GET); + + let result = content_encoder(BytesMut::new(), &mut req); + + match result { + Output::Empty(buf) => { + assert_eq!(buf.len(), 0); + assert!(!req.headers().contains_key(CONTENT_LENGTH)); + }, + _ => panic!("Unexpected result, should be Output::Empty"), + } + + req.set_method(Method::PUT); + + let result = content_encoder(BytesMut::new(), &mut req); + + match result { + Output::Empty(buf) => { + assert_eq!(buf.len(), 0); + let content_len = req.headers().get(CONTENT_LENGTH).expect("To set Content-Length for empty PUT"); + assert_eq!(content_len, "0"); + }, + _ => panic!("Unexpected result, should be Output::Empty"), + } + + req.set_method(Method::DELETE); + + let result = content_encoder(BytesMut::new(), &mut req); + + match result { + Output::Empty(buf) => { + assert_eq!(buf.len(), 0); + assert!(!req.headers().contains_key(CONTENT_LENGTH)); + }, + _ => panic!("Unexpected result, should be Output::Empty"), + } + + req.set_method(Method::PATCH); + + let result = content_encoder(BytesMut::new(), &mut req); + + match result { + Output::Empty(buf) => { + assert_eq!(buf.len(), 0); + let content_len = req.headers().get(CONTENT_LENGTH).expect("To set Content-Length for empty PATCH"); + assert_eq!(content_len, "0"); + }, + _ => panic!("Unexpected result, should be Output::Empty"), + } + + + } +}