From 3ccbce6bc833959c61f9fd2eb440b2cc7370d0cd Mon Sep 17 00:00:00 2001 From: "Robert G. Jakabosky" Date: Sat, 1 Sep 2018 00:08:53 +0800 Subject: [PATCH 1/5] Fix issue with 'Connection: close' in ClientRequest --- src/client/parser.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/client/parser.rs b/src/client/parser.rs index dd4e60bc5..5dd163395 100644 --- a/src/client/parser.rs +++ b/src/client/parser.rs @@ -41,7 +41,8 @@ impl HttpResponseParser { // if buf is empty parse_message will always return NotReady, let's avoid that if buf.is_empty() { match io.read_available(buf) { - Ok(Async::Ready((_, true))) => { + Ok(Async::Ready((true, true))) => (), + Ok(Async::Ready((false, true))) => { return Err(HttpResponseParserError::Disconnect) } Ok(Async::Ready((_, false))) => (), @@ -63,7 +64,8 @@ impl HttpResponseParser { return Err(HttpResponseParserError::Error(ParseError::TooLarge)); } match io.read_available(buf) { - Ok(Async::Ready((_, true))) => { + Ok(Async::Ready((true, true))) => (), + Ok(Async::Ready((false, true))) => { return Err(HttpResponseParserError::Disconnect) } Ok(Async::Ready((_, false))) => (), From 487519acec5d419146a3493f03bd1fba44b56b5b Mon Sep 17 00:00:00 2001 From: "Robert G. Jakabosky" Date: Sat, 1 Sep 2018 00:34:19 +0800 Subject: [PATCH 2/5] Add client test for 'Connection: close' as reported in issue #495 --- tests/test_client.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/test_client.rs b/tests/test_client.rs index d7341ce1f..d4a2ce1f3 100644 --- a/tests/test_client.rs +++ b/tests/test_client.rs @@ -66,6 +66,16 @@ fn test_simple() { assert_eq!(bytes, Bytes::from_static(STR.as_ref())); } +#[test] +fn test_connection_close() { + let mut srv = + test::TestServer::new(|app| app.handler(|_| HttpResponse::Ok().body(STR))); + + let request = srv.get().header("Connection", "close").finish().unwrap(); + let response = srv.execute(request.send()).unwrap(); + assert!(response.status().is_success()); +} + #[test] fn test_with_query_parameter() { let mut srv = test::TestServer::new(|app| { From 23416561734c925ba678284d02b4e4c56b11a699 Mon Sep 17 00:00:00 2001 From: "Robert G. Jakabosky" Date: Sat, 1 Sep 2018 01:41:38 +0800 Subject: [PATCH 3/5] Simplify buffer reading logic. Remove duplicate code. --- src/client/parser.rs | 24 +++++------------------- 1 file changed, 5 insertions(+), 19 deletions(-) diff --git a/src/client/parser.rs b/src/client/parser.rs index 5dd163395..7348de32a 100644 --- a/src/client/parser.rs +++ b/src/client/parser.rs @@ -38,20 +38,17 @@ impl HttpResponseParser { where T: IoStream, { - // if buf is empty parse_message will always return NotReady, let's avoid that - if buf.is_empty() { + loop { match io.read_available(buf) { - Ok(Async::Ready((true, true))) => (), Ok(Async::Ready((false, true))) => { return Err(HttpResponseParserError::Disconnect) } - Ok(Async::Ready((_, false))) => (), + Ok(Async::Ready(_)) => (), Ok(Async::NotReady) => return Ok(Async::NotReady), - Err(err) => return Err(HttpResponseParserError::Error(err.into())), + Err(err) => { + return Err(HttpResponseParserError::Error(err.into())) + } } - } - - loop { match HttpResponseParser::parse_message(buf) .map_err(HttpResponseParserError::Error)? { @@ -63,17 +60,6 @@ impl HttpResponseParser { if buf.capacity() >= MAX_BUFFER_SIZE { return Err(HttpResponseParserError::Error(ParseError::TooLarge)); } - match io.read_available(buf) { - Ok(Async::Ready((true, true))) => (), - Ok(Async::Ready((false, true))) => { - return Err(HttpResponseParserError::Disconnect) - } - Ok(Async::Ready((_, false))) => (), - Ok(Async::NotReady) => return Ok(Async::NotReady), - Err(err) => { - return Err(HttpResponseParserError::Error(err.into())) - } - } } } } From a42a8a2321bfb1d32599206f70105b085d08387e Mon Sep 17 00:00:00 2001 From: "Robert G. Jakabosky" Date: Sat, 1 Sep 2018 02:15:36 +0800 Subject: [PATCH 4/5] Add some comments to clarify logic. --- src/client/parser.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/client/parser.rs b/src/client/parser.rs index 7348de32a..b6f4ea3f7 100644 --- a/src/client/parser.rs +++ b/src/client/parser.rs @@ -39,6 +39,7 @@ impl HttpResponseParser { T: IoStream, { loop { + // Read some more data into the buffer for the parser. match io.read_available(buf) { Ok(Async::Ready((false, true))) => { return Err(HttpResponseParserError::Disconnect) @@ -49,6 +50,8 @@ impl HttpResponseParser { return Err(HttpResponseParserError::Error(err.into())) } } + + // Call HTTP response parser. match HttpResponseParser::parse_message(buf) .map_err(HttpResponseParserError::Error)? { @@ -60,6 +63,7 @@ impl HttpResponseParser { if buf.capacity() >= MAX_BUFFER_SIZE { return Err(HttpResponseParserError::Error(ParseError::TooLarge)); } + // Parser needs more data. Loop and read more data. } } } From 66881d7dd196eb7a588b576e6e4654362c326cf4 Mon Sep 17 00:00:00 2001 From: "Robert G. Jakabosky" Date: Sat, 1 Sep 2018 02:25:05 +0800 Subject: [PATCH 5/5] If buffer is empty, read more data before calling parser. --- src/client/parser.rs | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/src/client/parser.rs b/src/client/parser.rs index b6f4ea3f7..5fd81da25 100644 --- a/src/client/parser.rs +++ b/src/client/parser.rs @@ -39,6 +39,23 @@ impl HttpResponseParser { T: IoStream, { loop { + // Don't call parser until we have data to parse. + if !buf.is_empty() { + match HttpResponseParser::parse_message(buf) + .map_err(HttpResponseParserError::Error)? + { + Async::Ready((msg, decoder)) => { + self.decoder = decoder; + return Ok(Async::Ready(msg)); + } + Async::NotReady => { + if buf.capacity() >= MAX_BUFFER_SIZE { + return Err(HttpResponseParserError::Error(ParseError::TooLarge)); + } + // Parser needs more data. + } + } + } // Read some more data into the buffer for the parser. match io.read_available(buf) { Ok(Async::Ready((false, true))) => { @@ -50,22 +67,6 @@ impl HttpResponseParser { return Err(HttpResponseParserError::Error(err.into())) } } - - // Call HTTP response parser. - match HttpResponseParser::parse_message(buf) - .map_err(HttpResponseParserError::Error)? - { - Async::Ready((msg, decoder)) => { - self.decoder = decoder; - return Ok(Async::Ready(msg)); - } - Async::NotReady => { - if buf.capacity() >= MAX_BUFFER_SIZE { - return Err(HttpResponseParserError::Error(ParseError::TooLarge)); - } - // Parser needs more data. Loop and read more data. - } - } } }