From 61b1030882781f93c0228b5605041a197e5eb8f5 Mon Sep 17 00:00:00 2001
From: Nikolay Kim <fafhrd91@gmail.com>
Date: Thu, 8 Nov 2018 20:35:47 -0800
Subject: [PATCH] Fix websockets connection drop if request contains
 content-length header #567

---
 CHANGES.md              |  2 ++
 Cargo.toml              |  4 ++--
 src/server/h1decoder.rs | 31 +++++++++++++++++++++++++------
 src/server/service.rs   |  2 +-
 4 files changed, 30 insertions(+), 9 deletions(-)

diff --git a/CHANGES.md b/CHANGES.md
index 617237417..b1717ea92 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -11,6 +11,8 @@
 
 ### Fixed
 
+* Fix websockets connection drop if request contains "content-length" header #567
+
 * Fix keep-alive timer reset
 
 * HttpServer now treats streaming bodies the same for HTTP/1.x protocols. #549
diff --git a/Cargo.toml b/Cargo.toml
index 0dcce54b0..4abb64e27 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -61,8 +61,8 @@ flate2-rust = ["flate2/rust_backend"]
 cell = ["actix-net/cell"]
 
 [dependencies]
-actix = "^0.7.5"
-actix-net = "0.2.0"
+actix = "0.7.6"
+actix-net = "0.2.1"
 
 askama_escape = "0.1.0"
 base64 = "0.10"
diff --git a/src/server/h1decoder.rs b/src/server/h1decoder.rs
index 434dc42df..10f7e68a0 100644
--- a/src/server/h1decoder.rs
+++ b/src/server/h1decoder.rs
@@ -43,7 +43,9 @@ impl H1Decoder {
     }
 
     pub fn decode<H>(
-        &mut self, src: &mut BytesMut, settings: &ServiceConfig<H>,
+        &mut self,
+        src: &mut BytesMut,
+        settings: &ServiceConfig<H>,
     ) -> Result<Option<Message>, DecoderError> {
         // read payload
         if self.decoder.is_some() {
@@ -80,7 +82,9 @@ impl H1Decoder {
     }
 
     fn parse_message<H>(
-        &self, buf: &mut BytesMut, settings: &ServiceConfig<H>,
+        &self,
+        buf: &mut BytesMut,
+        settings: &ServiceConfig<H>,
     ) -> Poll<(Request, Option<EncodingDecoder>), ParseError> {
         // Parse http message
         let mut has_upgrade = false;
@@ -178,6 +182,13 @@ impl H1Decoder {
                             }
                             header::UPGRADE => {
                                 has_upgrade = true;
+                                // check content-length, some clients (dart)
+                                // sends "content-length: 0" with websocket upgrade
+                                if let Ok(val) = value.to_str() {
+                                    if val == "websocket" {
+                                        content_length = None;
+                                    }
+                                }
                             }
                             _ => (),
                         }
@@ -221,7 +232,9 @@ pub(crate) struct HeaderIndex {
 
 impl HeaderIndex {
     pub(crate) fn record(
-        bytes: &[u8], headers: &[httparse::Header], indices: &mut [HeaderIndex],
+        bytes: &[u8],
+        headers: &[httparse::Header],
+        indices: &mut [HeaderIndex],
     ) {
         let bytes_ptr = bytes.as_ptr() as usize;
         for (header, indices) in headers.iter().zip(indices.iter_mut()) {
@@ -369,7 +382,10 @@ macro_rules! byte (
 
 impl ChunkedState {
     fn step(
-        &self, body: &mut BytesMut, size: &mut u64, buf: &mut Option<Bytes>,
+        &self,
+        body: &mut BytesMut,
+        size: &mut u64,
+        buf: &mut Option<Bytes>,
     ) -> Poll<ChunkedState, io::Error> {
         use self::ChunkedState::*;
         match *self {
@@ -432,7 +448,8 @@ impl ChunkedState {
         }
     }
     fn read_size_lf(
-        rdr: &mut BytesMut, size: &mut u64,
+        rdr: &mut BytesMut,
+        size: &mut u64,
     ) -> Poll<ChunkedState, io::Error> {
         match byte!(rdr) {
             b'\n' if *size > 0 => Ok(Async::Ready(ChunkedState::Body)),
@@ -445,7 +462,9 @@ impl ChunkedState {
     }
 
     fn read_body(
-        rdr: &mut BytesMut, rem: &mut u64, buf: &mut Option<Bytes>,
+        rdr: &mut BytesMut,
+        rem: &mut u64,
+        buf: &mut Option<Bytes>,
     ) -> Poll<ChunkedState, io::Error> {
         trace!("Chunked read, remaining={:?}", rem);
 
diff --git a/src/server/service.rs b/src/server/service.rs
index cd4b3d3fa..e3402e305 100644
--- a/src/server/service.rs
+++ b/src/server/service.rs
@@ -88,7 +88,7 @@ where
         Ok(Async::Ready(()))
     }
 
-    fn call(&mut self, mut req: Self::Request) -> Self::Future {
+    fn call(&mut self, req: Self::Request) -> Self::Future {
         HttpChannel::new(self.settings.clone(), req)
     }
 }