From e439d0546b992687dc57ab4d7b3b7a1dc2e320a6 Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Wed, 3 Jan 2018 18:21:34 -0800 Subject: [PATCH] * fix force_close * shutdown io before exit * fix response creation with body from pool --- src/application.rs | 2 +- src/channel.rs | 4 +++- src/context.rs | 11 ---------- src/h1.rs | 53 +++++++++++++++++++++++++-------------------- src/h1writer.rs | 16 +++++++++----- src/h2writer.rs | 2 +- src/httpresponse.rs | 2 +- src/pipeline.rs | 2 +- src/router.rs | 2 ++ 9 files changed, 48 insertions(+), 46 deletions(-) diff --git a/src/application.rs b/src/application.rs index 8c284e71e..1e4d8273c 100644 --- a/src/application.rs +++ b/src/application.rs @@ -48,7 +48,7 @@ impl PipelineHandler for Inner { if path.is_empty() { req.match_info_mut().add("tail", ""); } else { - req.match_info_mut().add("tail", path.trim_left_matches('/')); + req.match_info_mut().add("tail", path.split_at(1).1); } return handler.handle(req) } diff --git a/src/channel.rs b/src/channel.rs index 633a05952..d736fd202 100644 --- a/src/channel.rs +++ b/src/channel.rs @@ -79,7 +79,9 @@ impl HttpChannel } } -/*impl Drop for HttpChannel { +/*impl Drop for HttpChannel + where T: AsyncRead + AsyncWrite + 'static, H: HttpHandler + 'static +{ fn drop(&mut self) { println!("Drop http channel"); } diff --git a/src/context.rs b/src/context.rs index 1cdb6b9b4..dff9344a2 100644 --- a/src/context.rs +++ b/src/context.rs @@ -14,7 +14,6 @@ use actix::dev::{AsyncContextApi, ActorAddressCell, ActorItemsCell, ActorWaitCel use body::{Body, Binary}; use error::{Error, Result}; use httprequest::HttpRequest; -use httpresponse::HttpResponse; pub trait ActorHttpContext: 'static { @@ -124,16 +123,6 @@ impl HttpContext where A: Actor { self.act = Some(actor); self } - - pub fn with_actor(mut self, actor: A, mut resp: HttpResponse) -> Result { - if self.act.is_some() { - panic!("Actor is set already"); - } - self.act = Some(actor); - - resp.replace_body(Body::Actor(Box::new(self))); - Ok(resp) - } } impl HttpContext where A: Actor { diff --git a/src/h1.rs b/src/h1.rs index f49d0a2e7..e4d2930b0 100644 --- a/src/h1.rs +++ b/src/h1.rs @@ -97,11 +97,11 @@ impl Http1 (self.settings, self.stream.into_inner(), self.addr, self.read_buf.freeze()) } - fn poll_completed(&mut self) -> Result { + fn poll_completed(&mut self, shutdown: bool) -> Result { // check stream state - match self.stream.poll_completed() { - Ok(Async::Ready(_)) => Ok(false), - Ok(Async::NotReady) => Ok(true), + match self.stream.poll_completed(shutdown) { + Ok(Async::Ready(_)) => Ok(true), + Ok(Async::NotReady) => Ok(false), Err(err) => { debug!("Error sending data: {}", err); Err(()) @@ -136,7 +136,7 @@ impl Http1 if !io && !item.flags.contains(EntryFlags::EOF) { if item.flags.contains(EntryFlags::ERROR) { // check stream state - if let Ok(Async::NotReady) = self.stream.poll_completed() { + if let Ok(Async::NotReady) = self.stream.poll_completed(true) { return Ok(Async::NotReady) } return Err(()) @@ -147,12 +147,10 @@ impl Http1 not_ready = false; // overide keep-alive state - if self.settings.keep_alive_enabled() { - if self.stream.keepalive() { - self.flags.insert(Flags::KEEPALIVE); - } else { - self.flags.remove(Flags::KEEPALIVE); - } + if self.stream.keepalive() { + self.flags.insert(Flags::KEEPALIVE); + } else { + self.flags.remove(Flags::KEEPALIVE); } self.stream.reset(); @@ -172,7 +170,7 @@ impl Http1 item.flags.insert(EntryFlags::ERROR); // check stream state, we still can have valid data in buffer - if let Ok(Async::NotReady) = self.stream.poll_completed() { + if let Ok(Async::NotReady) = self.stream.poll_completed(true) { return Ok(Async::NotReady) } return Err(()) @@ -207,11 +205,14 @@ impl Http1 // no keep-alive if !self.flags.contains(Flags::KEEPALIVE) && self.tasks.is_empty() { + let h2 = self.flags.contains(Flags::H2); + // check stream state - if self.poll_completed()? { + if !self.poll_completed(!h2)? { return Ok(Async::NotReady) } - if self.flags.contains(Flags::H2) { + + if h2 { return Ok(Async::Ready(Http1Result::Switch)) } else { return Ok(Async::Ready(Http1Result::Done)) @@ -284,7 +285,7 @@ impl Http1 } } Ok(Async::NotReady) => { - // start keep-alive timer, this is also slow request timeout + // start keep-alive timer, this also is slow request timeout if self.tasks.is_empty() { if self.settings.keep_alive_enabled() { let keep_alive = self.settings.keep_alive(); @@ -300,17 +301,20 @@ impl Http1 } } else { // check stream state - if self.poll_completed()? { + if !self.poll_completed(true)? { return Ok(Async::NotReady) } // keep-alive disable, drop connection return Ok(Async::Ready(Http1Result::Done)) } - } else { - // check stream state - self.poll_completed()?; - // keep-alive unset, rely on operating system + } else if !self.poll_completed(false)? || + self.flags.contains(Flags::KEEPALIVE) + { + // check stream state or + // if keep-alive unset, rely on operating system return Ok(Async::NotReady) + } else { + return Ok(Async::Ready(Http1Result::Done)) } } break @@ -320,12 +324,13 @@ impl Http1 // check for parse error if self.tasks.is_empty() { + let h2 = self.flags.contains(Flags::H2); + // check stream state - if self.poll_completed()? { + if !self.poll_completed(!h2)? { return Ok(Async::NotReady) } - - if self.flags.contains(Flags::H2) { + if h2 { return Ok(Async::Ready(Http1Result::Switch)) } if self.flags.contains(Flags::ERROR) || self.keepalive_timer.is_none() { @@ -334,7 +339,7 @@ impl Http1 } if not_ready { - self.poll_completed()?; + self.poll_completed(false)?; return Ok(Async::NotReady) } } diff --git a/src/h1writer.rs b/src/h1writer.rs index 5352e7435..200ff0529 100644 --- a/src/h1writer.rs +++ b/src/h1writer.rs @@ -33,7 +33,7 @@ pub trait Writer { fn write_eof(&mut self) -> Result; - fn poll_completed(&mut self) -> Poll<(), io::Error>; + fn poll_completed(&mut self, shutdown: bool) -> Poll<(), io::Error>; } bitflags! { @@ -94,7 +94,7 @@ impl H1Writer { while !buffer.is_empty() { match self.stream.write(buffer.as_ref()) { Ok(n) => { - buffer.split_to(n); + let _ = buffer.split_to(n); }, Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => { if buffer.len() > MAX_WRITE_BUFFER_SIZE { @@ -112,7 +112,6 @@ impl H1Writer { impl Writer for H1Writer { - #[cfg_attr(feature = "cargo-clippy", allow(cast_lossless))] fn written(&self) -> u64 { self.written } @@ -218,7 +217,6 @@ impl Writer for H1Writer { self.encoder.write_eof()?; if !self.encoder.is_eof() { - // debug!("last payload item, but it is not EOF "); Err(io::Error::new(io::ErrorKind::Other, "Last payload item, but eof is not reached")) } else if self.encoder.len() > MAX_WRITE_BUFFER_SIZE { @@ -228,9 +226,15 @@ impl Writer for H1Writer { } } - fn poll_completed(&mut self) -> Poll<(), io::Error> { + fn poll_completed(&mut self, shutdown: bool) -> Poll<(), io::Error> { match self.write_to_stream() { - Ok(WriterState::Done) => Ok(Async::Ready(())), + Ok(WriterState::Done) => { + if shutdown { + self.stream.shutdown() + } else { + Ok(Async::Ready(())) + } + }, Ok(WriterState::Pause) => Ok(Async::NotReady), Err(err) => Err(err) } diff --git a/src/h2writer.rs b/src/h2writer.rs index 9af11010f..57c4bd357 100644 --- a/src/h2writer.rs +++ b/src/h2writer.rs @@ -213,7 +213,7 @@ impl Writer for H2Writer { } } - fn poll_completed(&mut self) -> Poll<(), io::Error> { + fn poll_completed(&mut self, _shutdown: bool) -> Poll<(), io::Error> { match self.write_to_stream() { Ok(WriterState::Done) => Ok(Async::Ready(())), Ok(WriterState::Pause) => Ok(Async::NotReady), diff --git a/src/httpresponse.rs b/src/httpresponse.rs index 5d5e85fcb..f08553013 100644 --- a/src/httpresponse.rs +++ b/src/httpresponse.rs @@ -674,7 +674,7 @@ impl Pool { POOL.with(|pool| { if let Some(mut resp) = pool.borrow_mut().0.pop_front() { resp.status = status; - resp.body = Body::Empty; + resp.body = body; resp } else { Box::new(InnerHttpResponse::new(status, body)) diff --git a/src/pipeline.rs b/src/pipeline.rs index ad26266fa..44c503104 100644 --- a/src/pipeline.rs +++ b/src/pipeline.rs @@ -658,7 +658,7 @@ impl ProcessResponse { // flush io but only if we need to if self.running == RunningState::Paused || self.drain.is_some() { - match io.poll_completed() { + match io.poll_completed(false) { Ok(Async::Ready(_)) => { self.running.resume(); diff --git a/src/router.rs b/src/router.rs index ca6783413..560f7de79 100644 --- a/src/router.rs +++ b/src/router.rs @@ -189,6 +189,8 @@ impl Pattern { } /// Extract pattern parameters from the text + // This method unsafe internally, assumption that Pattern instance lives + // longer than `req` pub fn update_match_info(&self, req: &mut HttpRequest, prefix: usize) { if !self.names.is_empty() { let text: &str = unsafe{ mem::transmute(&req.path()[prefix..]) };