fix(client): improve HttpReader selection for client Responses

Closes #436
This commit is contained in:
Sean McArthur
2015-08-05 16:42:48 -07:00
parent af062ac954
commit 31f117ea08
4 changed files with 122 additions and 61 deletions

View File

@@ -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,