Skip to content

Commit 5c7195a

Browse files
committed
fix(http): fix several cases in HttpReader
- reading 0 bytes when SizedReader.remaining is more than 0 returns "early eof" error - reading 0 bytes when ChunkedReader.remaining is more than 0 returns "early eof" error - if SizedReader.remaining is less than buf.len(), the buf is sliced to the remaining size
1 parent 93e6d29 commit 5c7195a

File tree

1 file changed

+48
-3
lines changed

1 file changed

+48
-3
lines changed

src/http/h1.rs

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,8 @@ impl HttpMessage for Http11Message {
214214
}
215215
});
216216

217+
trace!("Http11Message.reader = {:?}", self.reader);
218+
217219

218220
Ok(ResponseHead {
219221
headers: headers,
@@ -456,9 +458,13 @@ impl<R: Read> Read for HttpReader<R> {
456458
if *remaining == 0 {
457459
Ok(0)
458460
} else {
459-
let num = try!(body.read(buf)) as u64;
461+
let to_read = min(*remaining as usize, buf.len());
462+
let num = try!(body.read(&mut buf[..to_read])) as u64;
463+
trace!("Sized read: {}", num);
460464
if num > *remaining {
461465
*remaining = 0;
466+
} else if num == 0 {
467+
return Err(io::Error::new(io::ErrorKind::Other, "early eof"));
462468
} else {
463469
*remaining -= num;
464470
}
@@ -486,6 +492,11 @@ impl<R: Read> Read for HttpReader<R> {
486492
let to_read = min(rem as usize, buf.len());
487493
let count = try!(body.read(&mut buf[..to_read])) as u64;
488494

495+
if count == 0 {
496+
*opt_remaining = Some(0);
497+
return Err(io::Error::new(io::ErrorKind::Other, "early eof"));
498+
}
499+
489500
rem -= count;
490501
*opt_remaining = if rem > 0 {
491502
Some(rem)
@@ -759,7 +770,12 @@ fn parse<R: Read, T: TryParse<Subject=I>, I>(rdr: &mut BufReader<R>) -> ::Result
759770

760771
fn try_parse<R: Read, T: TryParse<Subject=I>, I>(rdr: &mut BufReader<R>) -> TryParseResult<I> {
761772
let mut headers = [httparse::EMPTY_HEADER; MAX_HEADERS];
762-
<T as TryParse>::try_parse(&mut headers, rdr.get_buf())
773+
let buf = rdr.get_buf();
774+
if buf.len() == 0 {
775+
return Ok(httparse::Status::Partial);
776+
}
777+
trace!("try_parse({:?})", buf);
778+
<T as TryParse>::try_parse(&mut headers, buf)
763779
}
764780

765781
#[doc(hidden)]
@@ -776,9 +792,11 @@ impl<'a> TryParse for httparse::Request<'a, 'a> {
776792

777793
fn try_parse<'b>(headers: &'b mut [httparse::Header<'b>], buf: &'b [u8]) ->
778794
TryParseResult<(Method, RequestUri)> {
795+
trace!("Request.try_parse([Header; {}], [u8; {}])", headers.len(), buf.len());
779796
let mut req = httparse::Request::new(headers);
780797
Ok(match try!(req.parse(buf)) {
781798
httparse::Status::Complete(len) => {
799+
trace!("Request.try_parse Complete({})", len);
782800
httparse::Status::Complete((Incoming {
783801
version: if req.version.unwrap() == 1 { Http11 } else { Http10 },
784802
subject: (
@@ -798,9 +816,11 @@ impl<'a> TryParse for httparse::Response<'a, 'a> {
798816

799817
fn try_parse<'b>(headers: &'b mut [httparse::Header<'b>], buf: &'b [u8]) ->
800818
TryParseResult<RawStatus> {
819+
trace!("Response.try_parse([Header; {}], [u8; {}])", headers.len(), buf.len());
801820
let mut res = httparse::Response::new(headers);
802821
Ok(match try!(res.parse(buf)) {
803822
httparse::Status::Complete(len) => {
823+
trace!("Response.try_parse Complete({})", len);
804824
let code = res.code.unwrap();
805825
let reason = match StatusCode::from_u16(code).canonical_reason() {
806826
Some(reason) if reason == res.reason.unwrap() => Cow::Borrowed(reason),
@@ -837,7 +857,8 @@ pub const LINE_ENDING: &'static str = "\r\n";
837857

838858
#[cfg(test)]
839859
mod tests {
840-
use std::io::{self, Write};
860+
use std::error::Error;
861+
use std::io::{self, Read, Write};
841862

842863
use buffer::BufReader;
843864
use mock::MockStream;
@@ -909,6 +930,30 @@ mod tests {
909930
read_err("1;no CRLF");
910931
}
911932

933+
#[test]
934+
fn test_read_sized_early_eof() {
935+
let mut r = super::HttpReader::SizedReader(MockStream::with_input(b"foo bar"), 10);
936+
let mut buf = [0u8; 10];
937+
assert_eq!(r.read(&mut buf).unwrap(), 7);
938+
let e = r.read(&mut buf).unwrap_err();
939+
assert_eq!(e.kind(), io::ErrorKind::Other);
940+
assert_eq!(e.description(), "early eof");
941+
}
942+
943+
#[test]
944+
fn test_read_chunked_early_eof() {
945+
let mut r = super::HttpReader::ChunkedReader(MockStream::with_input(b"\
946+
9\r\n\
947+
foo bar\
948+
"), None);
949+
950+
let mut buf = [0u8; 10];
951+
assert_eq!(r.read(&mut buf).unwrap(), 7);
952+
let e = r.read(&mut buf).unwrap_err();
953+
assert_eq!(e.kind(), io::ErrorKind::Other);
954+
assert_eq!(e.description(), "early eof");
955+
}
956+
912957
#[test]
913958
fn test_parse_incoming() {
914959
let mut raw = MockStream::with_input(b"GET /echo HTTP/1.1\r\nHost: hyper.rs\r\n\r\n");

0 commit comments

Comments
 (0)