Repository: actix/actix-web
Pull request #496 (2018-08-31 16:10:19)

Fix issue with 'Connection: close' in ClientRequest
To fix issue #495 


Patch:
diff --git a/src/client/parser.rs b/src/client/parser.rs
index dd4e60bc..5fd81da2 100644
--- a/src/client/parser.rs
+++ b/src/client/parser.rs
@@ -38,42 +38,35 @@ impl HttpResponseParser {
     where
         T: IoStream,
     {
-        // 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))) => {
-                    return Err(HttpResponseParserError::Disconnect)
-                }
-                Ok(Async::Ready((_, false))) => (),
-                Ok(Async::NotReady) => return Ok(Async::NotReady),
-                Err(err) => return Err(HttpResponseParserError::Error(err.into())),
-            }
-        }
-
         loop {
-            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));
+            // 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));
                     }
-                    match io.read_available(buf) {
-                        Ok(Async::Ready((_, true))) => {
-                            return Err(HttpResponseParserError::Disconnect)
-                        }
-                        Ok(Async::Ready((_, false))) => (),
-                        Ok(Async::NotReady) => return Ok(Async::NotReady),
-                        Err(err) => {
-                            return Err(HttpResponseParserError::Error(err.into()))
+                    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))) => {
+                    return Err(HttpResponseParserError::Disconnect)
+                }
+                Ok(Async::Ready(_)) => (),
+                Ok(Async::NotReady) => return Ok(Async::NotReady),
+                Err(err) => {
+                    return Err(HttpResponseParserError::Error(err.into()))
+                }
+            }
         }
     }
 


Test patch:
diff --git a/tests/test_client.rs b/tests/test_client.rs
index d7341ce1..d4a2ce1f 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| {