From a56e5113eeabca8e1e84b46a4682a9882cefaf1e Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Sat, 24 Mar 2018 09:22:34 -0700 Subject: [PATCH] process transfer-encoding before content-length, fix tests on 32bit platform --- src/helpers.rs | 11 +++++++++++ src/server/h1.rs | 18 ++++++++++-------- src/server/h1writer.rs | 19 ++++++++----------- src/server/srv.rs | 4 ++-- 4 files changed, 31 insertions(+), 21 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 623869d0c..af76b52d5 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -150,6 +150,7 @@ pub(crate) fn write_status_line(version: Version, mut n: u16, bytes: &mut BytesM } } +/// NOTE: bytes object has to contain enough space pub(crate) fn write_content_length(mut n: usize, bytes: &mut BytesMut) { if n < 10 { let mut buf: [u8; 21] = [b'\r',b'\n',b'c',b'o',b'n',b't',b'e', @@ -244,24 +245,34 @@ mod tests { #[test] fn test_write_content_length() { let mut bytes = BytesMut::new(); + bytes.reserve(50); write_content_length(0, &mut bytes); assert_eq!(bytes.take().freeze(), b"\r\ncontent-length: 0\r\n"[..]); + bytes.reserve(50); write_content_length(9, &mut bytes); assert_eq!(bytes.take().freeze(), b"\r\ncontent-length: 9\r\n"[..]); + bytes.reserve(50); write_content_length(10, &mut bytes); assert_eq!(bytes.take().freeze(), b"\r\ncontent-length: 10\r\n"[..]); + bytes.reserve(50); write_content_length(99, &mut bytes); assert_eq!(bytes.take().freeze(), b"\r\ncontent-length: 99\r\n"[..]); + bytes.reserve(50); write_content_length(100, &mut bytes); assert_eq!(bytes.take().freeze(), b"\r\ncontent-length: 100\r\n"[..]); + bytes.reserve(50); write_content_length(101, &mut bytes); assert_eq!(bytes.take().freeze(), b"\r\ncontent-length: 101\r\n"[..]); + bytes.reserve(50); write_content_length(998, &mut bytes); assert_eq!(bytes.take().freeze(), b"\r\ncontent-length: 998\r\n"[..]); + bytes.reserve(50); write_content_length(1000, &mut bytes); assert_eq!(bytes.take().freeze(), b"\r\ncontent-length: 1000\r\n"[..]); + bytes.reserve(50); write_content_length(1001, &mut bytes); assert_eq!(bytes.take().freeze(), b"\r\ncontent-length: 1001\r\n"[..]); + bytes.reserve(50); write_content_length(5909, &mut bytes); assert_eq!(bytes.take().freeze(), b"\r\ncontent-length: 5909\r\n"[..]); } diff --git a/src/server/h1.rs b/src/server/h1.rs index 656c40c63..e1f61461b 100644 --- a/src/server/h1.rs +++ b/src/server/h1.rs @@ -494,6 +494,7 @@ impl Reader { // Parse http message let mut has_te = false; let mut has_upgrade = false; + let mut has_length = false; let msg = { let bytes_ptr = buf.as_ref().as_ptr() as usize; let mut headers: [httparse::Header; MAX_HEADERS] = @@ -505,10 +506,10 @@ impl Reader { match req.parse(b)? { httparse::Status::Complete(len) => { let method = Method::from_bytes( - req.method.unwrap_or("").as_bytes()) + req.method.unwrap().as_bytes()) .map_err(|_| ParseError::Method)?; let path = Uri::try_from(req.path.unwrap())?; - let version = if req.version.unwrap_or(1) == 1 { + let version = if req.version.unwrap() == 1 { Version::HTTP_11 } else { Version::HTTP_10 @@ -528,6 +529,7 @@ impl Reader { for header in headers[..headers_len].iter() { if let Ok(name) = HeaderName::from_bytes(header.name.as_bytes()) { has_te = has_te || name == header::TRANSFER_ENCODING; + has_length = has_length || name == header::CONTENT_LENGTH; has_upgrade = has_upgrade || name == header::UPGRADE; let v_start = header.value.as_ptr() as usize - bytes_ptr; let v_end = v_start + header.value.len(); @@ -547,10 +549,12 @@ impl Reader { msg }; - let decoder = if let Some(len) = - msg.get_ref().headers.get(header::CONTENT_LENGTH) - { + let decoder = if has_te && chunked(&msg.get_mut().headers)? { + // Chunked encoding + Some(Decoder::chunked()) + } else if has_length { // Content-Length + let len = msg.get_ref().headers.get(header::CONTENT_LENGTH).unwrap(); if let Ok(s) = len.to_str() { if let Ok(len) = s.parse::() { Some(Decoder::length(len)) @@ -562,10 +566,8 @@ impl Reader { debug!("illegal Content-Length: {:?}", len); return Err(ParseError::Header) } - } else if has_te && chunked(&msg.get_mut().headers)? { - // Chunked encoding - Some(Decoder::chunked()) } else if has_upgrade || msg.get_ref().method == Method::CONNECT { + // upgrade(websocket) or connect Some(Decoder::eof()) } else { None diff --git a/src/server/h1writer.rs b/src/server/h1writer.rs index c3eb5dc93..67b026e4e 100644 --- a/src/server/h1writer.rs +++ b/src/server/h1writer.rs @@ -134,24 +134,26 @@ impl Writer for H1Writer { // render message { let mut buffer = self.buffer.get_mut(); + let reason = msg.reason().as_bytes(); let mut is_bin = if let Body::Binary(ref bytes) = body { buffer.reserve( - 256 + msg.headers().len() * AVERAGE_HEADER_SIZE + bytes.len()); + 256 + msg.headers().len() * AVERAGE_HEADER_SIZE + + bytes.len() + reason.len()); true } else { - buffer.reserve(256 + msg.headers().len() * AVERAGE_HEADER_SIZE); + buffer.reserve( + 256 + msg.headers().len() * AVERAGE_HEADER_SIZE + reason.len()); false }; // status line helpers::write_status_line(version, msg.status().as_u16(), &mut buffer); - SharedBytes::extend_from_slice_(buffer, msg.reason().as_bytes()); + SharedBytes::extend_from_slice_(buffer, reason); match body { Body::Empty => if req.method != Method::HEAD { - SharedBytes::put_slice( - buffer, b"\r\ncontent-length: 0\r\n"); + SharedBytes::put_slice(buffer, b"\r\ncontent-length: 0\r\n"); } else { SharedBytes::put_slice(buffer, b"\r\n"); }, @@ -192,15 +194,10 @@ impl Writer for H1Writer { buf[pos..pos+2].copy_from_slice(b"\r\n"); pos += 2; remaining -= len; - - //buffer.put_slice(k); - //buffer.put_slice(b": "); - //buffer.put_slice(v); - //buffer.put_slice(b"\r\n"); } unsafe{buffer.advance_mut(pos)}; - // optimized date header + // optimized date header, set_date writes \r\n if !has_date { self.settings.set_date(&mut buffer); } else { diff --git a/src/server/srv.rs b/src/server/srv.rs index 4bb78b8bb..1ad41c58b 100644 --- a/src/server/srv.rs +++ b/src/server/srv.rs @@ -639,7 +639,7 @@ impl Handler for HttpServer // we need to stop system if server was spawned if slf.exit { - ctx.run_later(Duration::from_millis(500), |_, _| { + ctx.run_later(Duration::from_millis(300), |_, _| { Arbiter::system().do_send(actix::msgs::SystemExit(0)) }); } @@ -654,7 +654,7 @@ impl Handler for HttpServer } else { // we need to stop system if server was spawned if self.exit { - ctx.run_later(Duration::from_millis(500), |_, _| { + ctx.run_later(Duration::from_millis(300), |_, _| { Arbiter::system().do_send(actix::msgs::SystemExit(0)) }); }