use std::cell::RefCell; use std::rc::Rc; use actix_http::{Error, Response}; use actix_service::boxed::{self, BoxedNewService, BoxedService}; use actix_service::{ ApplyNewService, IntoNewService, IntoNewTransform, NewService, NewTransform, Service, }; use futures::future::{ok, Either, FutureResult}; use futures::{Async, Future, IntoFuture, Poll}; use crate::handler::{AsyncFactory, Factory, FromRequest}; use crate::responder::Responder; use crate::route::{CreateRouteService, Route, RouteService}; use crate::service::{ServiceRequest, ServiceResponse}; type HttpService

= BoxedService, ServiceResponse, ()>; type HttpNewService

= BoxedNewService<(), ServiceRequest

, ServiceResponse, (), ()>; /// 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 Resource> { routes: Vec>, endpoint: T, default: Rc>>>>, factory_ref: Rc>>>, } impl

Resource

{ pub fn new() -> Resource

{ let fref = Rc::new(RefCell::new(None)); Resource { routes: Vec::new(), endpoint: ResourceEndpoint::new(fref.clone()), factory_ref: fref, default: Rc::new(RefCell::new(None)), } } } impl

Default for Resource

{ fn default() -> Self { Self::new() } } impl Resource where T: NewService< Request = ServiceRequest

, Response = ServiceResponse, Error = (), InitError = (), >, { /// Register a new route and return mutable reference to *Route* object. /// *Route* is used for route configuration, i.e. adding predicates, /// setting up handler. /// /// ```rust,ignore /// use actix_web::*; /// /// fn main() { /// let app = App::new() /// .resource("/", |r| { /// r.route() /// .filter(pred::Any(pred::Get()).or(pred::Put())) /// .filter(pred::Header("Content-Type", "text/plain")) /// .f(|r| HttpResponse::Ok()) /// }) /// .finish(); /// } /// ``` pub fn route(mut self, route: Route

) -> Self { self.routes.push(route.finish()); self } /// Register a new route and add handler. /// /// ```rust,ignore /// # extern crate actix_web; /// use actix_web::*; /// fn index(req: HttpRequest) -> HttpResponse { unimplemented!() } /// /// App::new().resource("/", |r| r.with(index)); /// ``` /// /// This is shortcut for: /// /// ```rust,ignore /// # extern crate actix_web; /// # use actix_web::*; /// # fn index(req: HttpRequest) -> HttpResponse { unimplemented!() } /// App::new().resource("/", |r| r.route().with(index)); /// ``` pub fn to(mut self, handler: F) -> Self where F: Factory + 'static, I: FromRequest

+ 'static, R: Responder + 'static, { self.routes.push(Route::new().to(handler)); self } /// Register a new route and add async handler. /// /// ```rust,ignore /// # extern crate actix_web; /// # extern crate futures; /// use actix_web::*; /// use futures::future::Future; /// /// fn index(req: HttpRequest) -> Box> { /// unimplemented!() /// } /// /// App::new().resource("/", |r| r.with_async(index)); /// ``` /// /// This is shortcut for: /// /// ```rust,ignore /// # extern crate actix_web; /// # extern crate futures; /// # use actix_web::*; /// # use futures::future::Future; /// # fn index(req: HttpRequest) -> Box> { /// # unimplemented!() /// # } /// App::new().resource("/", |r| r.route().with_async(index)); /// ``` #[allow(clippy::wrong_self_convention)] pub fn to_async(mut self, handler: F) -> Self where F: AsyncFactory, I: FromRequest

+ 'static, R: IntoFuture + 'static, R::Item: Into, R::Error: Into, { self.routes.push(Route::new().to_async(handler)); self } /// Register a resource middleware /// /// This is similar to `App's` middlewares, but /// middlewares get invoked on resource level. pub fn middleware( self, mw: F, ) -> Resource< P, impl NewService< Request = ServiceRequest

, Response = ServiceResponse, Error = (), InitError = (), >, > where M: NewTransform< T::Service, Request = ServiceRequest

, Response = ServiceResponse, Error = (), InitError = (), >, F: IntoNewTransform, { let endpoint = ApplyNewService::new(mw, self.endpoint); Resource { endpoint, routes: self.routes, default: self.default, factory_ref: self.factory_ref, } } /// Default resource to be used if no matching route could be found. pub fn default_resource(mut self, f: F) -> Self where F: FnOnce(Resource

) -> R, R: IntoNewService, U: NewService< Request = ServiceRequest

, Response = ServiceResponse, Error = (), > + 'static, { // create and configure default resource self.default = Rc::new(RefCell::new(Some(Rc::new(boxed::new_service( f(Resource::new()).into_new_service().map_init_err(|_| ()), ))))); self } pub(crate) fn get_default(&self) -> Rc>>>> { self.default.clone() } } impl IntoNewService for Resource where T: NewService< Request = ServiceRequest

, Response = ServiceResponse, Error = (), InitError = (), >, { fn into_new_service(self) -> T { *self.factory_ref.borrow_mut() = Some(ResourceFactory { routes: self.routes, default: self.default, }); self.endpoint } } pub struct ResourceFactory

{ routes: Vec>, default: Rc>>>>, } impl NewService for ResourceFactory

{ type Request = ServiceRequest

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

; type Future = CreateResourceService

; fn new_service(&self, _: &()) -> Self::Future { let default_fut = if let Some(ref default) = *self.default.borrow() { Some(default.new_service(&())) } else { None }; CreateResourceService { fut: self .routes .iter() .map(|route| CreateRouteServiceItem::Future(route.new_service(&()))) .collect(), default: None, default_fut, } } } enum CreateRouteServiceItem

{ Future(CreateRouteService

), Service(RouteService

), } pub struct CreateResourceService

{ fut: Vec>, default: Option>, default_fut: Option, Error = ()>>>, } impl

Future for CreateResourceService

{ type Item = ResourceService

; type Error = (); fn poll(&mut self) -> Poll { let mut done = true; if let Some(ref mut fut) = self.default_fut { match fut.poll()? { Async::Ready(default) => self.default = Some(default), Async::NotReady => done = false, } } // poll http services for item in &mut self.fut { match item { CreateRouteServiceItem::Future(ref mut fut) => match fut.poll()? { Async::Ready(route) => { *item = CreateRouteServiceItem::Service(route) } Async::NotReady => { done = false; } }, CreateRouteServiceItem::Service(_) => continue, }; } if done { let routes = self .fut .drain(..) .map(|item| match item { CreateRouteServiceItem::Service(service) => service, CreateRouteServiceItem::Future(_) => unreachable!(), }) .collect(); Ok(Async::Ready(ResourceService { routes, default: self.default.take(), })) } else { Ok(Async::NotReady) } } } pub struct ResourceService

{ routes: Vec>, default: Option>, } impl

Service for ResourceService

{ type Request = ServiceRequest

; type Response = ServiceResponse; type Error = (); type Future = Either< Box>, Either< Box>, FutureResult, >, >; fn poll_ready(&mut self) -> Poll<(), Self::Error> { Ok(Async::Ready(())) } fn call(&mut self, mut req: ServiceRequest

) -> Self::Future { for route in self.routes.iter_mut() { if route.check(&mut req) { return Either::A(route.call(req)); } } if let Some(ref mut default) = self.default { Either::B(Either::A(default.call(req))) } else { let req = req.into_request(); Either::B(Either::B(ok(ServiceResponse::new( req, Response::NotFound().finish(), )))) } } } #[doc(hidden)] pub struct ResourceEndpoint

{ factory: Rc>>>, } impl

ResourceEndpoint

{ fn new(factory: Rc>>>) -> Self { ResourceEndpoint { factory } } } impl NewService for ResourceEndpoint

{ type Request = ServiceRequest

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

; type Future = CreateResourceService

; fn new_service(&self, _: &()) -> Self::Future { self.factory.borrow_mut().as_mut().unwrap().new_service(&()) } }