From b61c2a0cf07d2b729aa0a9de841cf091cdb2d8bf Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Thu, 14 Dec 2017 11:20:45 -0800 Subject: [PATCH] handle keep-alive setting more efficient --- src/h1.rs | 17 ++++++++++------- src/h1writer.rs | 7 +------ src/h2.rs | 3 ++- src/h2writer.rs | 8 +------- src/middlewares/defaultheaders.rs | 25 ++++++++++++++++++++----- src/server.rs | 22 +++++++++++++++++----- 6 files changed, 51 insertions(+), 31 deletions(-) diff --git a/src/h1.rs b/src/h1.rs index fef40e56b..ba42584b3 100644 --- a/src/h1.rs +++ b/src/h1.rs @@ -94,8 +94,8 @@ impl Http1 pub fn poll(&mut self) -> Poll { // keep-alive timer - if let Some(ref mut timeout) = self.keepalive_timer { - match timeout.poll() { + if self.keepalive_timer.is_some() { + match self.keepalive_timer.as_mut().unwrap().poll() { Ok(Async::Ready(_)) => { trace!("Keep-alive timeout, close connection"); return Ok(Async::Ready(Http1Result::Done)) @@ -124,10 +124,12 @@ impl Http1 not_ready = false; // overide keep-alive state - if self.stream.keepalive() { - self.flags.insert(Flags::KEEPALIVE); - } else { - self.flags.remove(Flags::KEEPALIVE); + if self.settings.keep_alive_enabled() { + if self.stream.keepalive() { + self.flags.insert(Flags::KEEPALIVE); + } else { + self.flags.remove(Flags::KEEPALIVE); + } } self.stream.reset(); @@ -249,7 +251,8 @@ impl Http1 Ok(Async::NotReady) => { // start keep-alive timer, this is also slow request timeout if self.tasks.is_empty() { - if let Some(keep_alive) = self.settings.keep_alive() { + if self.settings.keep_alive_enabled() { + let keep_alive = self.settings.keep_alive(); if keep_alive > 0 && self.flags.contains(Flags::KEEPALIVE) { if self.keepalive_timer.is_none() { trace!("Start keep-alive timer"); diff --git a/src/h1writer.rs b/src/h1writer.rs index 956f752b3..ae4ef1644 100644 --- a/src/h1writer.rs +++ b/src/h1writer.rs @@ -2,7 +2,7 @@ use std::io; use futures::{Async, Poll}; use tokio_io::AsyncWrite; use http::Version; -use http::header::{HeaderValue, CONNECTION, CONTENT_TYPE, DATE}; +use http::header::{HeaderValue, CONNECTION, DATE}; use helpers; use body::Body; @@ -180,11 +180,6 @@ impl Writer for H1Writer { buffer.extend_from_slice(b"\r\n"); } - // default content-type - if !msg.headers().contains_key(CONTENT_TYPE) { - buffer.extend_from_slice(b"ContentType: application/octet-stream\r\n"); - } - // msg eof buffer.extend_from_slice(b"\r\n"); self.headers_size = buffer.len() as u32; diff --git a/src/h2.rs b/src/h2.rs index 9dd85a935..4b9b6c1d4 100644 --- a/src/h2.rs +++ b/src/h2.rs @@ -155,7 +155,8 @@ impl Http2 Ok(Async::NotReady) => { // start keep-alive timer if self.tasks.is_empty() { - if let Some(keep_alive) = self.settings.keep_alive() { + if self.settings.keep_alive_enabled() { + let keep_alive = self.settings.keep_alive(); if keep_alive > 0 && self.keepalive_timer.is_none() { trace!("Start keep-alive timer"); let mut timeout = Timeout::new( diff --git a/src/h2writer.rs b/src/h2writer.rs index 53a07b80f..afcca2da4 100644 --- a/src/h2writer.rs +++ b/src/h2writer.rs @@ -4,7 +4,7 @@ use futures::{Async, Poll}; use http2::{Reason, SendStream}; use http2::server::Respond; use http::{Version, HttpTryFrom, Response}; -use http::header::{HeaderValue, CONNECTION, CONTENT_TYPE, TRANSFER_ENCODING, DATE}; +use http::header::{HeaderValue, CONNECTION, TRANSFER_ENCODING, DATE}; use helpers; use body::Body; @@ -131,12 +131,6 @@ impl Writer for H2Writer { msg.headers_mut().insert(DATE, HeaderValue::try_from(&bytes[..]).unwrap()); } - // default content-type - if !msg.headers().contains_key(CONTENT_TYPE) { - msg.headers_mut().insert( - CONTENT_TYPE, HeaderValue::from_static("application/octet-stream")); - } - let mut resp = Response::new(()); *resp.status_mut() = msg.status(); *resp.version_mut() = Version::HTTP_2; diff --git a/src/middlewares/defaultheaders.rs b/src/middlewares/defaultheaders.rs index 3335847e0..3e9dc278a 100644 --- a/src/middlewares/defaultheaders.rs +++ b/src/middlewares/defaultheaders.rs @@ -1,6 +1,6 @@ //! Default response headers use http::{HeaderMap, HttpTryFrom}; -use http::header::{HeaderName, HeaderValue}; +use http::header::{HeaderName, HeaderValue, CONTENT_TYPE}; use httprequest::HttpRequest; use httpresponse::HttpResponse; @@ -27,22 +27,30 @@ use middlewares::{Response, Middleware}; /// .finish(); /// } /// ``` -pub struct DefaultHeaders(HeaderMap); +pub struct DefaultHeaders{ + ct: bool, + headers: HeaderMap, +} impl DefaultHeaders { pub fn build() -> DefaultHeadersBuilder { - DefaultHeadersBuilder{headers: Some(HeaderMap::new())} + DefaultHeadersBuilder{ct: false, headers: Some(HeaderMap::new())} } } impl Middleware for DefaultHeaders { fn response(&self, _: &mut HttpRequest, mut resp: Box) -> Response { - for (key, value) in self.0.iter() { + for (key, value) in self.headers.iter() { if !resp.headers().contains_key(key) { resp.headers_mut().insert(key, value.clone()); } } + // default content-type + if self.ct && !resp.headers().contains_key(CONTENT_TYPE) { + resp.headers_mut().insert( + CONTENT_TYPE, HeaderValue::from_static("application/octet-stream")); + } Response::Done(resp) } } @@ -50,6 +58,7 @@ impl Middleware for DefaultHeaders { /// Structure that follows the builder pattern for building `DefaultHeaders` middleware. #[derive(Debug)] pub struct DefaultHeadersBuilder { + ct: bool, headers: Option, } @@ -76,10 +85,16 @@ impl DefaultHeadersBuilder { self } + /// Set *CONTENT-TYPE* header if response does not contain this header. + pub fn content_type(&mut self) -> &mut Self { + self.ct = true; + self + } + /// Finishes building and returns the built `DefaultHeaders` middleware. pub fn finish(&mut self) -> DefaultHeaders { let headers = self.headers.take().expect("cannot reuse middleware builder"); - DefaultHeaders(headers) + DefaultHeaders{ ct: self.ct, headers: headers } } } diff --git a/src/server.rs b/src/server.rs index c85f0a729..bb9552a94 100644 --- a/src/server.rs +++ b/src/server.rs @@ -171,7 +171,7 @@ impl HttpServer for app in &mut apps { app.server_settings(settings.clone()); } - self.h = Some(Rc::new(WorkerSettings{h: apps, keep_alive: self.keep_alive})); + self.h = Some(Rc::new(WorkerSettings::new(apps, self.keep_alive))); // start server Ok(HttpServer::create(move |ctx| { @@ -411,23 +411,35 @@ struct Worker { pub(crate) struct WorkerSettings { h: Vec, - keep_alive: Option, + enabled: bool, + keep_alive: u64, } impl WorkerSettings { + fn new(h: Vec, keep_alive: Option) -> WorkerSettings { + WorkerSettings { + h: h, + enabled: if let Some(ka) = keep_alive { ka > 0 } else { false }, + keep_alive: keep_alive.unwrap_or(0), + } + } + pub fn handlers(&self) -> &Vec { &self.h } - pub fn keep_alive(&self) -> Option { + pub fn keep_alive(&self) -> u64 { self.keep_alive } + pub fn keep_alive_enabled(&self) -> bool { + self.enabled + } } impl Worker { fn new(h: Vec, handler: StreamHandlerType, keep_alive: Option) -> Worker { Worker { - h: Rc::new(WorkerSettings{h: h, keep_alive: keep_alive}), + h: Rc::new(WorkerSettings::new(h, keep_alive)), handler: handler, } } @@ -455,7 +467,7 @@ impl Handler> for Worker fn handle(&mut self, msg: IoStream, _: &mut Context) -> Response> { - if self.h.keep_alive.is_none() && + if !self.h.keep_alive_enabled() && msg.io.set_keepalive(Some(Duration::new(75, 0))).is_err() { error!("Can not set socket keep-alive option");