From 12dac9bdba9ab5e20b98d7e8b740c5216f62339b Mon Sep 17 00:00:00 2001 From: Sean McArthur Date: Sat, 6 Aug 2016 00:09:00 -0700 Subject: [PATCH 1/3] perf(http): encoder headers with a faster fmt::Write --- src/http/h1/parse.rs | 37 +++++++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/src/http/h1/parse.rs b/src/http/h1/parse.rs index ac08d8d9..86578914 100644 --- a/src/http/h1/parse.rs +++ b/src/http/h1/parse.rs @@ -1,5 +1,5 @@ use std::borrow::Cow; -use std::io::Write; +use std::fmt::{self, Write}; use httparse; @@ -95,8 +95,12 @@ impl Http1Message for ServerMessage { let init_cap = 30 + head.headers.len() * AVERAGE_HEADER_SIZE; dst.reserve(init_cap); debug!("writing {:#?}", head.headers); - let _ = write!(dst, "{} {}\r\n{}\r\n", head.version, head.subject, head.headers); - + if head.version == ::HttpVersion::Http11 && head.subject == ::StatusCode::Ok { + extend(dst, b"HTTP/1.1 200 OK\r\n"); + let _ = write!(FastWrite(dst), "{}\r\n", head.headers); + } else { + let _ = write!(FastWrite(dst), "{} {}\r\n{}\r\n", head.version, head.subject, head.headers); + } body } } @@ -195,12 +199,37 @@ impl Http1Message for ClientMessage { let init_cap = 30 + head.headers.len() * AVERAGE_HEADER_SIZE; dst.reserve(init_cap); debug!("writing {:#?}", head.headers); - let _ = write!(dst, "{} {}\r\n{}\r\n", head.subject, head.version, head.headers); + let _ = write!(FastWrite(dst), "{} {}\r\n{}\r\n", head.subject, head.version, head.headers); body } } +struct FastWrite<'a>(&'a mut Vec); + +impl<'a> fmt::Write for FastWrite<'a> { + fn write_str(&mut self, s: &str) -> fmt::Result { + extend(self.0, s.as_bytes()); + Ok(()) + } + + fn write_fmt(&mut self, args: fmt::Arguments) -> fmt::Result { + fmt::write(self, args) + } +} + +fn extend(dst: &mut Vec, data: &[u8]) { + use std::ptr; + dst.reserve(data.len()); + let prev = dst.len(); + unsafe { + ptr::copy_nonoverlapping(data.as_ptr(), + dst.as_mut_ptr().offset(prev as isize), + data.len()); + dst.set_len(prev + data.len()); + } +} + #[cfg(test)] mod tests { use http; From 523b890a19e9325938adf42456eea6191fcb8029 Mon Sep 17 00:00:00 2001 From: Sean McArthur Date: Sat, 6 Aug 2016 00:10:46 -0700 Subject: [PATCH 2/3] fix(server): support HTTP/1.1 pipelining --- src/http/conn.rs | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/http/conn.rs b/src/http/conn.rs index 187d7c6c..8fa4caba 100644 --- a/src/http/conn.rs +++ b/src/http/conn.rs @@ -117,10 +117,16 @@ impl> ConnInner { } fn parse(&mut self) -> ::Result>::Message as Http1Message>::Incoming>> { - let n = try!(self.buf.read_from(&mut self.transport)); - if n == 0 { - trace!("parse eof"); - return Err(io::Error::new(io::ErrorKind::UnexpectedEof, "parse eof").into()); + match self.buf.read_from(&mut self.transport) { + Ok(0) => { + trace!("parse eof"); + return Err(io::Error::new(io::ErrorKind::UnexpectedEof, "parse eof").into()); + } + Ok(_) => {}, + Err(e) => match e.kind() { + io::ErrorKind::WouldBlock => {}, + _ => return Err(e.into()) + } } match try!(http::parse::<>::Message, _>(self.buf.bytes())) { Some((head, len)) => { @@ -444,9 +450,9 @@ impl> ConnInner { state } - fn can_read_more(&self) -> bool { + fn can_read_more(&self, was_init: bool) -> bool { match self.state { - State::Init { .. } => false, + State::Init { .. } => !was_init && !self.buf.is_empty(), _ => !self.buf.is_empty() } } @@ -549,6 +555,11 @@ impl> Conn { events }; + let was_init = match self.0.state { + State::Init { .. } => true, + _ => false + }; + if events.is_readable() { self.0.on_readable(scope); } @@ -570,7 +581,7 @@ impl> Conn { }, }; - if events.is_readable() && self.0.can_read_more() { + if events.is_readable() && self.0.can_read_more(was_init) { return self.ready(events, scope); } From a3a815c09cb2478b57b9af301bf021701b01abc2 Mon Sep 17 00:00:00 2001 From: Sean McArthur Date: Sat, 6 Aug 2016 00:11:45 -0700 Subject: [PATCH 3/3] perf(http): reduce server loops when headers and body are ready --- src/http/conn.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/http/conn.rs b/src/http/conn.rs index 8fa4caba..f8548325 100644 --- a/src/http/conn.rs +++ b/src/http/conn.rs @@ -324,7 +324,7 @@ impl> ConnInner { } }; let mut head = http::MessageHead::default(); - let interest = handler.on_outgoing(&mut head); + let mut interest = handler.on_outgoing(&mut head); if head.version == HttpVersion::Http11 { let mut buf = Vec::new(); let keep_alive = self.keep_alive_enabled && head.should_keep_alive(); @@ -339,6 +339,7 @@ impl> ConnInner { bytes: buf, pos: 0 }); + interest = handler.on_encode(&mut Encoder::h1(&mut encoder, &mut self.transport)); Writing::Ready(encoder) }, _ => Writing::Chunk(Chunk { @@ -370,7 +371,7 @@ impl> ConnInner { } Writing::Head => { let mut head = http::MessageHead::default(); - let interest = handler.on_outgoing(&mut head); + let mut interest = handler.on_outgoing(&mut head); // if the request wants to close, server cannot stop it if *keep_alive { // if the request wants to stay alive, then it depends @@ -389,6 +390,7 @@ impl> ConnInner { bytes: buf, pos: 0 }); + interest = handler.on_encode(&mut Encoder::h1(&mut encoder, &mut self.transport)); Writing::Ready(encoder) }, _ => Writing::Chunk(Chunk {