From 7c4b814e6b95bdb22b11e027b2da16c5abb8399f Mon Sep 17 00:00:00 2001 From: Sean McArthur Date: Fri, 27 Oct 2017 10:26:59 -0700 Subject: [PATCH] fix(client): don't read extra bytes on idle connections --- src/proto/conn.rs | 53 +++++++++++++++++++++++++++++-------------- src/proto/h1/parse.rs | 8 +++++++ src/proto/mod.rs | 1 + tests/client.rs | 32 ++++++++++++++++++++++++++ 4 files changed, 77 insertions(+), 17 deletions(-) diff --git a/src/proto/conn.rs b/src/proto/conn.rs index 823ae8b4bf..e6e09dd45c 100644 --- a/src/proto/conn.rs +++ b/src/proto/conn.rs @@ -102,7 +102,16 @@ where I: AsyncRead + AsyncWrite, pub fn can_read_head(&self) -> bool { match self.state.reading { - Reading::Init => true, + Reading::Init => { + if T::should_read_first() { + true + } else { + match self.state.writing { + Writing::Init => false, + _ => true, + } + } + } _ => false, } } @@ -840,25 +849,35 @@ mod tests { #[test] fn test_conn_init_read_eof_busy() { - // server ignores - let io = AsyncIo::new_buf(vec![], 1); - let mut conn = Conn::<_, proto::Chunk, ServerTransaction>::new(io, Default::default()); - conn.state.busy(); + let _: Result<(), ()> = future::lazy(|| { + // server ignores + let io = AsyncIo::new_buf(vec![], 1); + let mut conn = Conn::<_, proto::Chunk, ServerTransaction>::new(io, Default::default()); + conn.state.busy(); - match conn.poll().unwrap() { - Async::Ready(None) => {}, - other => panic!("unexpected frame: {:?}", other) - } + match conn.poll().unwrap() { + Async::Ready(None) => {}, + other => panic!("unexpected frame: {:?}", other) + } - // client, when busy, returns the error - let io = AsyncIo::new_buf(vec![], 1); - let mut conn = Conn::<_, proto::Chunk, ClientTransaction>::new(io, Default::default()); - conn.state.busy(); + // client + let io = AsyncIo::new_buf(vec![], 1); + let mut conn = Conn::<_, proto::Chunk, ClientTransaction>::new(io, Default::default()); + conn.state.busy(); - match conn.poll() { - Err(ref err) if err.kind() == ::std::io::ErrorKind::UnexpectedEof => {}, - other => panic!("unexpected frame: {:?}", other) - } + match conn.poll() { + Ok(Async::NotReady) => {}, + other => panic!("unexpected frame: {:?}", other) + } + + // once mid-request, returns the error + conn.state.writing = super::Writing::KeepAlive; + match conn.poll() { + Err(ref err) if err.kind() == ::std::io::ErrorKind::UnexpectedEof => {}, + other => panic!("unexpected frame: {:?}", other) + } + Ok(()) + }).wait(); } #[test] diff --git a/src/proto/h1/parse.rs b/src/proto/h1/parse.rs index 93a96a6e7c..d993d928fd 100644 --- a/src/proto/h1/parse.rs +++ b/src/proto/h1/parse.rs @@ -136,6 +136,10 @@ impl Http1Transaction for ServerTransaction { fn should_error_on_parse_eof() -> bool { false } + + fn should_read_first() -> bool { + true + } } impl ServerTransaction { @@ -289,6 +293,10 @@ impl Http1Transaction for ClientTransaction { fn should_error_on_parse_eof() -> bool { true } + + fn should_read_first() -> bool { + false + } } impl ClientTransaction { diff --git a/src/proto/mod.rs b/src/proto/mod.rs index 11552557ab..15de1345a9 100644 --- a/src/proto/mod.rs +++ b/src/proto/mod.rs @@ -149,6 +149,7 @@ pub trait Http1Transaction { fn encode(head: MessageHead, has_body: bool, method: &mut Option, dst: &mut Vec) -> h1::Encoder; fn should_error_on_parse_eof() -> bool; + fn should_read_first() -> bool; } pub type ParseResult = ::Result, usize)>>; diff --git a/tests/client.rs b/tests/client.rs index 5a5cb5bfa6..2120b9dc32 100644 --- a/tests/client.rs +++ b/tests/client.rs @@ -353,6 +353,38 @@ test! { body: None, } +test! { + name: client_pipeline_responses_extra, + + server: + expected: "\ + GET /pipe HTTP/1.1\r\n\ + Host: {addr}\r\n\ + \r\n\ + ", + reply: "\ + HTTP/1.1 200 OK\r\n\ + Content-Length: 0\r\n\ + \r\n\ + HTTP/1.1 200 OK\r\n\ + Content-Length: 0\r\n\ + \r\n\ + ", + + client: + request: + method: Get, + url: "http://{addr}/pipe", + headers: [], + body: None, + proxy: false, + response: + status: Ok, + headers: [], + body: None, +} + + test! { name: client_error_unexpected_eof,