diff --git a/src/server/h1.rs b/src/server/h1.rs index 739c6651..5ae841bd 100644 --- a/src/server/h1.rs +++ b/src/server/h1.rs @@ -447,7 +447,7 @@ where }); continue 'outer; } - Err(msg) => { + Err(_) => { // handler is not found self.tasks.push_back(Entry { pipe: EntryPipe::Error(ServerError::err( @@ -516,19 +516,22 @@ mod tests { use std::{cmp, io, time}; use bytes::{Buf, Bytes, BytesMut}; + use futures::future; use http::{Method, Version}; + use tokio::runtime::current_thread; use tokio_io::{AsyncRead, AsyncWrite}; use super::*; - use application::HttpApplication; + use application::{App, HttpApplication}; use httpmessage::HttpMessage; use server::h1decoder::Message; + use server::handler::IntoHttpHandler; use server::settings::{ServerSettings, WorkerSettings}; use server::{KeepAlive, Request}; fn wrk_settings() -> WorkerSettings { WorkerSettings::::new( - Vec::new(), + App::new().into_handler(), KeepAlive::Os, ServerSettings::default(), ) @@ -646,30 +649,6 @@ mod tests { } } - #[test] - fn test_req_parse1() { - let buf = Buffer::new("GET /test HTTP/1.1\r\n\r\n"); - let readbuf = BytesMut::new(); - let settings = wrk_settings(); - - let mut h1 = Http1::new(settings.clone(), buf, None, readbuf, false, None); - h1.poll_io(); - h1.poll_io(); - assert_eq!(h1.tasks.len(), 1); - } - - #[test] - fn test_req_parse2() { - let buf = Buffer::new(""); - let readbuf = - BytesMut::from(Vec::::from(&b"GET /test HTTP/1.1\r\n\r\n"[..])); - let settings = wrk_settings(); - - let mut h1 = Http1::new(settings.clone(), buf, None, readbuf, true, None); - h1.poll_io(); - assert_eq!(h1.tasks.len(), 1); - } - #[test] fn test_req_parse_err() { let buf = Buffer::new("GET /test HTTP/1\r\n\r\n"); diff --git a/src/server/h2.rs b/src/server/h2.rs index a7cf8aec..f31c2db3 100644 --- a/src/server/h2.rs +++ b/src/server/h2.rs @@ -370,7 +370,7 @@ impl Entry { // start request processing let task = match settings.handler().handle(msg) { Ok(task) => EntryPipe::Task(task), - Err(msg) => EntryPipe::Error(ServerError::err( + Err(_) => EntryPipe::Error(ServerError::err( Version::HTTP_2, StatusCode::NOT_FOUND, )), diff --git a/src/server/handler.rs b/src/server/handler.rs new file mode 100644 index 00000000..0700e196 --- /dev/null +++ b/src/server/handler.rs @@ -0,0 +1,189 @@ +use futures::{Async, Poll}; + +use super::message::Request; +use super::Writer; +use error::Error; + +/// Low level http request handler +#[allow(unused_variables)] +pub trait HttpHandler: 'static { + /// Request handling task + type Task: HttpHandlerTask; + + /// Handle request + fn handle(&self, req: Request) -> Result; +} + +impl HttpHandler for Box>> { + type Task = Box; + + fn handle(&self, req: Request) -> Result, Request> { + self.as_ref().handle(req) + } +} + +/// Low level http request handler +pub trait HttpHandlerTask { + /// Poll task, this method is used before or after *io* object is available + fn poll_completed(&mut self) -> Poll<(), Error> { + Ok(Async::Ready(())) + } + + /// Poll task when *io* object is available + fn poll_io(&mut self, io: &mut Writer) -> Poll; + + /// Connection is disconnected + fn disconnected(&mut self) {} +} + +impl HttpHandlerTask for Box { + fn poll_io(&mut self, io: &mut Writer) -> Poll { + self.as_mut().poll_io(io) + } +} + +/// Conversion helper trait +pub trait IntoHttpHandler { + /// The associated type which is result of conversion. + type Handler: HttpHandler; + + /// Convert into `HttpHandler` object. + fn into_handler(self) -> Self::Handler; +} + +impl IntoHttpHandler for T { + type Handler = T; + + fn into_handler(self) -> Self::Handler { + self + } +} + +impl IntoHttpHandler for Vec { + type Handler = VecHttpHandler; + + fn into_handler(self) -> Self::Handler { + VecHttpHandler(self.into_iter().map(|item| item.into_handler()).collect()) + } +} + +#[doc(hidden)] +pub struct VecHttpHandler(Vec); + +impl HttpHandler for VecHttpHandler { + type Task = H::Task; + + fn handle(&self, mut req: Request) -> Result { + for h in &self.0 { + req = match h.handle(req) { + Ok(task) => return Ok(task), + Err(e) => e, + }; + } + Err(req) + } +} + +macro_rules! http_handler ({$EN:ident, $(($n:tt, $T:ident)),+} => { + impl<$($T: HttpHandler,)+> HttpHandler for ($($T,)+) { + type Task = $EN<$($T,)+>; + + fn handle(&self, mut req: Request) -> Result { + $( + req = match self.$n.handle(req) { + Ok(task) => return Ok($EN::$T(task)), + Err(e) => e, + }; + )+ + Err(req) + } + } + + #[doc(hidden)] + pub enum $EN<$($T: HttpHandler,)+> { + $($T ($T::Task),)+ + } + + impl<$($T: HttpHandler,)+> HttpHandlerTask for $EN<$($T,)+> + { + fn poll_completed(&mut self) -> Poll<(), Error> { + match self { + $($EN :: $T(ref mut task) => task.poll_completed(),)+ + } + } + + fn poll_io(&mut self, io: &mut Writer) -> Poll { + match self { + $($EN::$T(ref mut task) => task.poll_io(io),)+ + } + } + + /// Connection is disconnected + fn disconnected(&mut self) { + match self { + $($EN::$T(ref mut task) => task.disconnected(),)+ + } + } + } +}); + +http_handler!(HttpHandlerTask1, (0, A)); +http_handler!(HttpHandlerTask2, (0, A), (1, B)); +http_handler!(HttpHandlerTask3, (0, A), (1, B), (2, C)); +http_handler!(HttpHandlerTask4, (0, A), (1, B), (2, C), (3, D)); +http_handler!(HttpHandlerTask5, (0, A), (1, B), (2, C), (3, D), (4, E)); +http_handler!( + HttpHandlerTask6, + (0, A), + (1, B), + (2, C), + (3, D), + (4, E), + (5, F) +); +http_handler!( + HttpHandlerTask7, + (0, A), + (1, B), + (2, C), + (3, D), + (4, E), + (5, F), + (6, G) +); +http_handler!( + HttpHandlerTask8, + (0, A), + (1, B), + (2, C), + (3, D), + (4, E), + (5, F), + (6, G), + (7, H) +); +http_handler!( + HttpHandlerTask9, + (0, A), + (1, B), + (2, C), + (3, D), + (4, E), + (5, F), + (6, G), + (7, H), + (8, I) +); +http_handler!( + HttpHandlerTask10, + (0, A), + (1, B), + (2, C), + (3, D), + (4, E), + (5, F), + (6, G), + (7, H), + (8, I), + (9, J) +); diff --git a/src/server/http.rs b/src/server/http.rs index faee041c..f67ebe95 100644 --- a/src/server/http.rs +++ b/src/server/http.rs @@ -3,7 +3,8 @@ use std::{io, mem, net, time}; use actix::{Actor, Addr, AsyncContext, Context, Handler, System}; use actix_net::server::{Server, ServerServiceFactory}; -use actix_net::{ssl, NewService, NewServiceExt, Service}; +use actix_net::service::{NewService, NewServiceExt, Service}; +use actix_net::ssl; use futures::future::{ok, FutureResult}; use futures::{Async, Poll, Stream}; diff --git a/src/server/mod.rs b/src/server/mod.rs index ec7e8e4e..75f75fcd 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -115,7 +115,7 @@ use futures::{Async, Poll}; use tokio_io::{AsyncRead, AsyncWrite}; use tokio_tcp::TcpStream; -pub use actix_net::{PauseServer, ResumeServer, StopServer}; +pub use actix_net::server::{PauseServer, ResumeServer, StopServer}; mod channel; mod error; @@ -124,25 +124,25 @@ pub(crate) mod h1decoder; mod h1writer; mod h2; mod h2writer; +mod handler; pub(crate) mod helpers; mod http; pub(crate) mod input; pub(crate) mod message; pub(crate) mod output; pub(crate) mod settings; - mod ssl; -pub use self::ssl::*; +pub use self::handler::*; pub use self::http::HttpServer; pub use self::message::Request; pub use self::settings::ServerSettings; +pub use self::ssl::*; #[doc(hidden)] pub use self::helpers::write_content_length; use body::Binary; -use error::Error; use extensions::Extensions; use header::ContentEncoding; use httpresponse::HttpResponse; @@ -222,61 +222,6 @@ impl From> for KeepAlive { } } -/// Low level http request handler -#[allow(unused_variables)] -pub trait HttpHandler: 'static { - /// Request handling task - type Task: HttpHandlerTask; - - /// Handle request - fn handle(&self, req: Request) -> Result; -} - -impl HttpHandler for Box>> { - type Task = Box; - - fn handle(&self, req: Request) -> Result, Request> { - self.as_ref().handle(req) - } -} - -/// Low level http request handler -pub trait HttpHandlerTask { - /// Poll task, this method is used before or after *io* object is available - fn poll_completed(&mut self) -> Poll<(), Error> { - Ok(Async::Ready(())) - } - - /// Poll task when *io* object is available - fn poll_io(&mut self, io: &mut Writer) -> Poll; - - /// Connection is disconnected - fn disconnected(&mut self) {} -} - -impl HttpHandlerTask for Box { - fn poll_io(&mut self, io: &mut Writer) -> Poll { - self.as_mut().poll_io(io) - } -} - -/// Conversion helper trait -pub trait IntoHttpHandler { - /// The associated type which is result of conversion. - type Handler: HttpHandler; - - /// Convert into `HttpHandler` object. - fn into_handler(self) -> Self::Handler; -} - -impl IntoHttpHandler for T { - type Handler = T; - - fn into_handler(self) -> Self::Handler { - self - } -} - #[doc(hidden)] #[derive(Debug)] pub enum WriterState { diff --git a/src/server/settings.rs b/src/server/settings.rs index 18a8c095..fe36c331 100644 --- a/src/server/settings.rs +++ b/src/server/settings.rs @@ -316,11 +316,8 @@ mod tests { let mut rt = current_thread::Runtime::new().unwrap(); let _ = rt.block_on(future::lazy(|| { - let settings = WorkerSettings::<()>::new( - Vec::new(), - KeepAlive::Os, - ServerSettings::default(), - ); + let settings = + WorkerSettings::<()>::new((), KeepAlive::Os, ServerSettings::default()); let mut buf1 = BytesMut::with_capacity(DATE_VALUE_LENGTH + 10); settings.set_date(&mut buf1, true); let mut buf2 = BytesMut::with_capacity(DATE_VALUE_LENGTH + 10);