diff --git a/src/conn.rs b/src/conn.rs index dbf8a6b..d352329 100644 --- a/src/conn.rs +++ b/src/conn.rs @@ -34,6 +34,8 @@ impl ConnectionPool { let is_secure = url.scheme().eq_ignore_ascii_case("https"); + let is_head = request.method.eq_ignore_ascii_case("head"); + let cookie_headers: Vec<_> = { match jar.as_ref() { None => vec![], @@ -131,7 +133,7 @@ impl ConnectionPool { send_body(body, do_chunk, &mut stream)?; // since it is not a redirect, give away the incoming stream to the response object - resp.set_stream(stream); + resp.set_stream(stream, is_head); // release the response Ok(resp) diff --git a/src/response.rs b/src/response.rs index 9d6b3a7..b712d75 100644 --- a/src/response.rs +++ b/src/response.rs @@ -37,6 +37,7 @@ pub struct Response { index: (usize, usize), // index into status_line where we split: HTTP/1.1 200 OK status: u16, headers: Vec
, + is_head: bool, stream: Option, } @@ -242,12 +243,22 @@ impl Response { /// assert_eq!(bytes.len(), len); /// ``` pub fn into_reader(self) -> impl Read { + let is_chunked = self.header("transfer-encoding") .map(|enc| enc.len() > 0) // whatever it says, do chunked .unwrap_or(false); + let len = self.header("content-length") .and_then(|l| l.parse::().ok()); + let reader = self.stream.expect("No reader in response?!"); + + // head requests never have a body + if self.is_head { + return Box::new(LimitedRead::new(reader, 0)) as Box; + } + + // figure out how to make a reader match is_chunked { true => Box::new(chunked_transfer::Decoder::new(reader)), false => match len { @@ -372,11 +383,13 @@ impl Response { index, status, headers, + is_head: false, stream: None, }) } - fn set_stream(&mut self, stream: Stream) { + fn set_stream(&mut self, stream: Stream, is_head: bool) { + self.is_head = is_head; self.stream = Some(stream); } @@ -418,7 +431,7 @@ impl FromStr for Response { let bytes = s.as_bytes().to_owned(); let mut cursor = Cursor::new(bytes); let mut resp = Self::do_from_read(&mut cursor)?; - resp.set_stream(Stream::Cursor(cursor)); + resp.set_stream(Stream::Cursor(cursor), false); Ok(resp) } } diff --git a/src/test/body_read.rs b/src/test/body_read.rs index d21cada..078c86d 100644 --- a/src/test/body_read.rs +++ b/src/test/body_read.rs @@ -60,3 +60,23 @@ fn ignore_content_length_when_chunked() { reader.read_to_string(&mut text).unwrap(); assert_eq!(text, "hello world!!!"); } + +#[test] +fn no_reader_on_head() { + test::set_handler("/no_reader_on_head", |_req, _url| { + // so this is technically illegal, we return a body for the HEAD request. + test::make_response( + 200, + "OK", + vec!["Content-Length: 4", "transfer-encoding: chunked"], + "3\r\nhel\r\nb\r\nlo world!!!\r\n0\r\n\r\n" + .to_string() + .into_bytes(), + ) + }); + let resp = head("test://host/no_reader_on_head").call(); + let mut reader = resp.into_reader(); + let mut text = String::new(); + reader.read_to_string(&mut text).unwrap(); + assert_eq!(text, ""); +}