use std::marker::PhantomData; use std::rc::Rc; use actix_http::{http::Method, Error, Response}; use actix_service::{NewService, Service}; use futures::{Async, Future, IntoFuture, Poll}; use crate::filter::{self, Filter}; use crate::handler::{AsyncFactory, AsyncHandle, Extract, Factory, FromRequest, Handle}; use crate::responder::Responder; use crate::service::{ServiceRequest, ServiceResponse}; type BoxedRouteService = Box< Service< Request = Req, Response = Res, Error = (), Future = Box>, >, >; type BoxedRouteNewService = Box< NewService< Request = Req, Response = Res, Error = (), InitError = (), Service = BoxedRouteService, Future = Box, Error = ()>>, >, >; /// Resource route definition /// /// Route uses builder-like pattern for configuration. /// If handler is not explicitly set, default *404 Not Found* handler is used. pub struct Route

{ service: BoxedRouteNewService, ServiceResponse>, filters: Rc>>, } impl Route

{ pub fn build() -> RouteBuilder

{ RouteBuilder::new() } pub fn get() -> RouteBuilder

{ RouteBuilder::new().method(Method::GET) } pub fn post() -> RouteBuilder

{ RouteBuilder::new().method(Method::POST) } pub fn put() -> RouteBuilder

{ RouteBuilder::new().method(Method::PUT) } pub fn delete() -> RouteBuilder

{ RouteBuilder::new().method(Method::DELETE) } } impl

NewService for Route

{ type Request = ServiceRequest

; type Response = ServiceResponse; type Error = (); type InitError = (); type Service = RouteService

; type Future = CreateRouteService

; fn new_service(&self, _: &()) -> Self::Future { CreateRouteService { fut: self.service.new_service(&()), filters: self.filters.clone(), } } } type RouteFuture

= Box< Future, ServiceResponse>, Error = ()>, >; pub struct CreateRouteService

{ fut: RouteFuture

, filters: Rc>>, } impl

Future for CreateRouteService

{ type Item = RouteService

; type Error = (); fn poll(&mut self) -> Poll { match self.fut.poll()? { Async::Ready(service) => Ok(Async::Ready(RouteService { service, filters: self.filters.clone(), })), Async::NotReady => Ok(Async::NotReady), } } } pub struct RouteService

{ service: BoxedRouteService, ServiceResponse>, filters: Rc>>, } impl

RouteService

{ pub fn check(&self, req: &mut ServiceRequest

) -> bool { for f in self.filters.iter() { if !f.check(req.request()) { return false; } } true } } impl

Service for RouteService

{ type Request = ServiceRequest

; type Response = ServiceResponse; type Error = (); type Future = Box>; fn poll_ready(&mut self) -> Poll<(), Self::Error> { self.service.poll_ready() } fn call(&mut self, req: Self::Request) -> Self::Future { self.service.call(req) } } pub struct RouteBuilder

{ filters: Vec>, _t: PhantomData

, } impl RouteBuilder

{ fn new() -> RouteBuilder

{ RouteBuilder { filters: Vec::new(), _t: PhantomData, } } /// Add method match filter to the route. /// /// ```rust,ignore /// # extern crate actix_web; /// # use actix_web::*; /// # fn main() { /// App::new().resource("/path", |r| { /// r.route() /// .filter(pred::Get()) /// .filter(pred::Header("content-type", "text/plain")) /// .f(|req| HttpResponse::Ok()) /// }) /// # .finish(); /// # } /// ``` pub fn method(mut self, method: Method) -> Self { self.filters.push(Box::new(filter::Method(method))); self } /// Add filter to the route. /// /// ```rust,ignore /// # extern crate actix_web; /// # use actix_web::*; /// # fn main() { /// App::new().resource("/path", |r| { /// r.route() /// .filter(pred::Get()) /// .filter(pred::Header("content-type", "text/plain")) /// .f(|req| HttpResponse::Ok()) /// }) /// # .finish(); /// # } /// ``` pub fn filter(mut self, f: F) -> Self { self.filters.push(Box::new(f)); self } // pub fn map>( // self, // md: F, // ) -> RouteServiceBuilder // where // T: NewService< // Request = HandlerRequest, // Response = HandlerRequest, // InitError = (), // >, // { // RouteServiceBuilder { // service: md.into_new_service(), // filters: self.filters, // _t: PhantomData, // } // } /// Set handler function, use request extractor for parameters. /// /// ```rust,ignore /// # extern crate bytes; /// # extern crate actix_web; /// # extern crate futures; /// #[macro_use] extern crate serde_derive; /// use actix_web::{http, App, Path, Result}; /// /// #[derive(Deserialize)] /// struct Info { /// username: String, /// } /// /// /// extract path info using serde /// fn index(info: Path) -> Result { /// Ok(format!("Welcome {}!", info.username)) /// } /// /// fn main() { /// let app = App::new().resource( /// "/{username}/index.html", // <- define path parameters /// |r| r.method(http::Method::GET).with(index), /// ); // <- use `with` extractor /// } /// ``` /// /// It is possible to use multiple extractors for one handler function. /// /// ```rust,ignore /// # extern crate bytes; /// # extern crate actix_web; /// # extern crate futures; /// #[macro_use] extern crate serde_derive; /// # use std::collections::HashMap; /// use actix_web::{http, App, Json, Path, Query, Result}; /// /// #[derive(Deserialize)] /// struct Info { /// username: String, /// } /// /// /// extract path info using serde /// fn index( /// path: Path, query: Query>, body: Json, /// ) -> Result { /// Ok(format!("Welcome {}!", path.username)) /// } /// /// fn main() { /// let app = App::new().resource( /// "/{username}/index.html", // <- define path parameters /// |r| r.method(http::Method::GET).with(index), /// ); // <- use `with` extractor /// } /// ``` pub fn to(self, handler: F) -> Route

where F: Factory + 'static, T: FromRequest

+ 'static, R: Responder + 'static, { Route { service: Box::new(RouteNewService::new( Extract::new().and_then(Handle::new(handler).map_err(|_| panic!())), )), filters: Rc::new(self.filters), } } /// Set async handler function, use request extractor for parameters. /// Also this method needs to be used if your handler function returns /// `impl Future<>` /// /// ```rust,ignore /// # extern crate bytes; /// # extern crate actix_web; /// # extern crate futures; /// #[macro_use] extern crate serde_derive; /// use actix_web::{http, App, Error, Path}; /// use futures::Future; /// /// #[derive(Deserialize)] /// struct Info { /// username: String, /// } /// /// /// extract path info using serde /// fn index(info: Path) -> Box> { /// unimplemented!() /// } /// /// fn main() { /// let app = App::new().resource( /// "/{username}/index.html", // <- define path parameters /// |r| r.method(http::Method::GET).with_async(index), /// ); // <- use `with` extractor /// } /// ``` #[allow(clippy::wrong_self_convention)] pub fn to_async(self, handler: F) -> Route

where F: AsyncFactory, T: FromRequest

+ 'static, R: IntoFuture + 'static, R::Item: Into, R::Error: Into, { Route { service: Box::new(RouteNewService::new( Extract::new().and_then(AsyncHandle::new(handler).map_err(|_| panic!())), )), filters: Rc::new(self.filters), } } } // pub struct RouteServiceBuilder { // service: T, // filters: Vec>, // _t: PhantomData<(P, U1, U2)>, // } // impl RouteServiceBuilder // where // T: NewService< // Request = HandlerRequest, // Response = HandlerRequest, // Error = Error, // InitError = (), // >, // { // pub fn new>(factory: F) -> Self { // RouteServiceBuilder { // service: factory.into_new_service(), // filters: Vec::new(), // _t: PhantomData, // } // } // /// Add method match filter to the route. // /// // /// ```rust // /// # extern crate actix_web; // /// # use actix_web::*; // /// # fn main() { // /// App::new().resource("/path", |r| { // /// r.route() // /// .filter(pred::Get()) // /// .filter(pred::Header("content-type", "text/plain")) // /// .f(|req| HttpResponse::Ok()) // /// }) // /// # .finish(); // /// # } // /// ``` // pub fn method(mut self, method: Method) -> Self { // self.filters.push(Box::new(filter::Method(method))); // self // } // /// Add filter to the route. // /// // /// ```rust // /// # extern crate actix_web; // /// # use actix_web::*; // /// # fn main() { // /// App::new().resource("/path", |r| { // /// r.route() // /// .filter(pred::Get()) // /// .filter(pred::Header("content-type", "text/plain")) // /// .f(|req| HttpResponse::Ok()) // /// }) // /// # .finish(); // /// # } // /// ``` // pub fn filter + 'static>(&mut self, f: F) -> &mut Self { // self.filters.push(Box::new(f)); // self // } // pub fn map>( // self, // md: F, // ) -> RouteServiceBuilder< // impl NewService< // Request = HandlerRequest, // Response = HandlerRequest, // Error = Error, // InitError = (), // >, // S, // U1, // U2, // > // where // T1: NewService< // Request = HandlerRequest, // Response = HandlerRequest, // InitError = (), // >, // T1::Error: Into, // { // RouteServiceBuilder { // service: self // .service // .and_then(md.into_new_service().map_err(|e| e.into())), // filters: self.filters, // _t: PhantomData, // } // } // pub fn to_async(self, handler: F) -> Route // where // F: AsyncFactory, // P: FromRequest + 'static, // R: IntoFuture, // R::Item: Into, // R::Error: Into, // { // Route { // service: self // .service // .and_then(Extract::new(P::Config::default())) // .then(AsyncHandle::new(handler)), // filters: Rc::new(self.filters), // } // } // pub fn to(self, handler: F) -> Route // where // F: Factory + 'static, // P: FromRequest + 'static, // R: Responder + 'static, // { // Route { // service: Box::new(RouteNewService::new( // self.service // .and_then(Extract::new(P::Config::default())) // .and_then(Handle::new(handler)), // )), // filters: Rc::new(self.filters), // } // } // } struct RouteNewService where T: NewService, Error = (Error, ServiceRequest

)>, { service: T, } impl RouteNewService where T: NewService< Request = ServiceRequest

, Response = ServiceResponse, Error = (Error, ServiceRequest

), >, T::Future: 'static, T::Service: 'static, ::Future: 'static, { pub fn new(service: T) -> Self { RouteNewService { service } } } impl NewService for RouteNewService where T: NewService< Request = ServiceRequest

, Response = ServiceResponse, Error = (Error, ServiceRequest

), >, T::Future: 'static, T::Service: 'static, ::Future: 'static, { type Request = ServiceRequest

; type Response = ServiceResponse; type Error = (); type InitError = (); type Service = BoxedRouteService; type Future = Box>; fn new_service(&self, _: &()) -> Self::Future { Box::new( self.service .new_service(&()) .map_err(|_| ()) .and_then(|service| { let service: BoxedRouteService<_, _> = Box::new(RouteServiceWrapper { service }); Ok(service) }), ) } } struct RouteServiceWrapper>> { service: T, } impl Service for RouteServiceWrapper where T::Future: 'static, T: Service< Request = ServiceRequest

, Response = ServiceResponse, Error = (Error, ServiceRequest

), >, { type Request = ServiceRequest

; type Response = ServiceResponse; type Error = (); type Future = Box>; fn poll_ready(&mut self) -> Poll<(), Self::Error> { self.service.poll_ready().map_err(|_| ()) } fn call(&mut self, req: ServiceRequest

) -> Self::Future { Box::new(self.service.call(req).then(|res| match res { Ok(res) => Ok(res), Err((err, req)) => Ok(req.error_response(err)), })) } }