fix(client): improve HttpReader selection for client Responses
Closes #436
This commit is contained in:
		| @@ -36,6 +36,7 @@ use version; | ||||
| /// An implementation of the `HttpMessage` trait for HTTP/1.1. | ||||
| #[derive(Debug)] | ||||
| pub struct Http11Message { | ||||
|     method: Option<Method>, | ||||
|     stream: Option<Box<NetworkStream + Send>>, | ||||
|     writer: Option<HttpWriter<BufWriter<Box<NetworkStream + Send>>>>, | ||||
|     reader: Option<HttpReader<BufReader<Box<NetworkStream + Send>>>>, | ||||
| @@ -91,8 +92,8 @@ impl HttpMessage for Http11Message { | ||||
|         try!(write!(&mut stream, "{} {} {}{}", | ||||
|                     head.method, uri, version, LINE_ENDING)); | ||||
|  | ||||
|         let stream = match head.method { | ||||
|             Method::Get | Method::Head => { | ||||
|         let stream = match &head.method { | ||||
|             &Method::Get | &Method::Head => { | ||||
|                 debug!("headers={:?}", head.headers); | ||||
|                 try!(write!(&mut stream, "{}{}", head.headers, LINE_ENDING)); | ||||
|                 EmptyWriter(stream) | ||||
| @@ -137,6 +138,7 @@ impl HttpMessage for Http11Message { | ||||
|             } | ||||
|         }; | ||||
|  | ||||
|         self.method = Some(head.method.clone()); | ||||
|         self.writer = Some(stream); | ||||
|  | ||||
|         Ok(head) | ||||
| @@ -159,30 +161,37 @@ impl HttpMessage for Http11Message { | ||||
|         let raw_status = head.subject; | ||||
|         let headers = head.headers; | ||||
|  | ||||
|         let body = if headers.has::<TransferEncoding>() { | ||||
|             match headers.get::<TransferEncoding>() { | ||||
|                 Some(&TransferEncoding(ref codings)) => { | ||||
|                     if codings.len() > 1 { | ||||
|                         trace!("TODO: #2 handle other codings: {:?}", codings); | ||||
|                     }; | ||||
|  | ||||
|                     if codings.contains(&Chunked) { | ||||
|         let method = self.method.take().unwrap_or(Method::Get); | ||||
|         // According to https://tools.ietf.org/html/rfc7230#section-3.3.3 | ||||
|         // 1. HEAD reponses, and Status 1xx, 204, and 304 cannot have a body. | ||||
|         // 2. Status 2xx to a CONNECT cannot have a body. | ||||
|         // 3. Transfer-Encoding: chunked has a chunked body. | ||||
|         // 4. If multiple differing Content-Length headers or invalid, close connection. | ||||
|         // 5. Content-Length header has a sized body. | ||||
|         // 6. Not Client. | ||||
|         // 7. Read till EOF. | ||||
|         let body = match (method, raw_status.0) { | ||||
|             (Method::Head, _) => EmptyReader(stream), | ||||
|             (_, 100...199) | (_, 204) | (_, 304) => EmptyReader(stream), | ||||
|             (Method::Connect, 200...299) => EmptyReader(stream), | ||||
|             _ => { | ||||
|                  if let Some(&TransferEncoding(ref codings)) = headers.get() { | ||||
|                     if codings.last() == Some(&Chunked) { | ||||
|                         ChunkedReader(stream, None) | ||||
|                     } else { | ||||
|                         trace!("not chuncked. read till eof"); | ||||
|                         EofReader(stream) | ||||
|                     } | ||||
|                 } else if let Some(&ContentLength(len)) =  headers.get() { | ||||
|                     SizedReader(stream, len) | ||||
|                 } else if headers.has::<ContentLength>() { | ||||
|                     trace!("illegal Content-Length: {:?}", headers.get_raw("Content-Length")); | ||||
|                     return Err(Error::Header); | ||||
|                 } else { | ||||
|                     trace!("neither Transfer-Encoding nor Content-Length"); | ||||
|                     EofReader(stream) | ||||
|                 } | ||||
|                 None => unreachable!() | ||||
|             } | ||||
|         } else if headers.has::<ContentLength>() { | ||||
|             match headers.get::<ContentLength>() { | ||||
|                 Some(&ContentLength(len)) => SizedReader(stream, len), | ||||
|                 None => unreachable!() | ||||
|             } | ||||
|         } else { | ||||
|             trace!("neither Transfer-Encoding nor Content-Length"); | ||||
|             EofReader(stream) | ||||
|         }; | ||||
|  | ||||
|         self.reader = Some(body); | ||||
| @@ -259,6 +268,7 @@ impl Http11Message { | ||||
|     /// the peer. | ||||
|     pub fn with_stream(stream: Box<NetworkStream + Send>) -> Http11Message { | ||||
|         Http11Message { | ||||
|             method: None, | ||||
|             stream: Some(stream), | ||||
|             writer: None, | ||||
|             reader: None, | ||||
|   | ||||
		Reference in New Issue
	
	Block a user