From c9ffb90aebdc77a8fade2e4196f311f9bbfcce82 Mon Sep 17 00:00:00 2001 From: Liu Jiang Date: Sat, 28 Mar 2020 16:04:18 +0800 Subject: [PATCH] Handle ErrorKind::Interrupted when doing stream IO When doing IO with the underlying stream object, we should handle the special case of ErrorKind::Interrupted, otherwise the connection will be closed incorrectly. Quotation from Rust doc: An error of the [`ErrorKind::Interrupted`] kind is non-fatal and the read operation should be retried if there is nothing else to do. Signed-off-by: Liu Jiang --- coverage_config.json | 2 +- src/connection.rs | 26 ++++++++++++-------------- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/coverage_config.json b/coverage_config.json index 4f21e4e..258501e 100644 --- a/coverage_config.json +++ b/coverage_config.json @@ -1 +1 @@ -{"coverage_score": 93.2, "exclude_path": "", "crate_features": ""} +{"coverage_score": 92.8, "exclude_path": "", "crate_features": ""} diff --git a/src/connection.rs b/src/connection.rs index 450ecdb..898bcc3 100644 --- a/src/connection.rs +++ b/src/connection.rs @@ -117,18 +117,16 @@ impl HttpConnection { // Reads a maximum of `BUFFER_SIZE` bytes from the stream into `buffer`. // The return value represents the end index of what we have just appended. fn read_bytes(&mut self) -> Result { - // Append new bytes to what we already have in the buffer. - let bytes_read = self - .stream - .read(&mut self.buffer[self.read_cursor..]) - .map_err(ConnectionError::StreamError)?; - - // If the read returned 0 then the client has closed the connection. - if bytes_read == 0 { - return Err(ConnectionError::ConnectionClosed); + loop { + // Append new bytes to what we already have in the buffer. + match self.stream.read(&mut self.buffer[self.read_cursor..]) { + // If the read returned 0 then the client has closed the connection. + Ok(0) => return Err(ConnectionError::ConnectionClosed), + Ok(bytes_read) => return Ok(bytes_read + self.read_cursor), + Err(e) if e.kind() == std::io::ErrorKind::Interrupted => continue, + Err(e) => return Err(ConnectionError::StreamError(e)), + } } - - Ok(bytes_read + self.read_cursor) } // Parses bytes in `buffer` for a valid request line. @@ -324,9 +322,7 @@ impl HttpConnection { if let Some(response_buffer_vec) = self.response_buffer.as_mut() { let bytes_to_be_written = response_buffer_vec.len(); match self.stream.write(response_buffer_vec.as_slice()) { - Ok(0) | Err(_) => { - connection_closed = true; - } + Ok(0) => connection_closed = true, Ok(bytes_written) => { if bytes_written != bytes_to_be_written { response_buffer_vec.drain(..bytes_written); @@ -334,6 +330,8 @@ impl HttpConnection { response_fully_written = true; } } + Err(e) if e.kind() == std::io::ErrorKind::Interrupted => {} + Err(_) => connection_closed = true, } }