use std::cell::RefCell; use std::rc::Rc; use actix_http::{http::Method, 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, RouteBuilder, RouteService}; use crate::service::{ServiceRequest, ServiceResponse}; type HttpService
= BoxedService = 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 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
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 ) -> Route ,
{
self.routes.push(f(Route::build()));
self
}
/// Register a new `GET` route.
pub fn get + 'static,
R: Responder + 'static,
{
self.routes.push(Route::get().to(f));
self
}
/// Register a new `POST` route.
pub fn post + 'static,
R: Responder + 'static,
{
self.routes.push(Route::post().to(f));
self
}
/// Register a new `PUT` route.
pub fn put + 'static,
R: Responder + 'static,
{
self.routes.push(Route::put().to(f));
self
}
/// Register a new `DELETE` route.
pub fn delete + 'static,
R: Responder + 'static,
{
self.routes.push(Route::delete().to(f));
self
}
/// Register a new `HEAD` route.
pub fn head + 'static,
R: Responder + 'static,
{
self.routes.push(Route::build().method(Method::HEAD).to(f));
self
}
/// Register a new route and add method check to route.
///
/// ```rust,ignore
/// # extern crate actix_web;
/// use actix_web::*;
/// fn index(req: &HttpRequest) -> HttpResponse { unimplemented!() }
///
/// App::new().resource("/", |r| r.method(http::Method::GET).f(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().filter(pred::Get()).f(index));
/// ```
pub fn method ) -> Route ,
{
self.routes.push(f(Route::build().method(method)));
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 + 'static,
R: Responder + 'static,
{
self.routes.push(Route::build().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 + 'static,
R: IntoFuture + 'static,
R::Item: Into ,
Response = ServiceResponse,
Error = (),
InitError = (),
>,
>
where
M: NewTransform<
T::Service,
Request = ServiceRequest ,
Response = ServiceResponse,
Error = (),
InitError = (),
>,
F: IntoNewTransform ) -> 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 IntoNewService
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 {
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 Future for CreateResourceService {
type Item = ResourceService ;
type Error = ();
fn poll(&mut self) -> Poll {
routes: Vec Service for ResourceService {
type Request = ServiceRequest ;
type Response = ServiceResponse;
type Error = ();
type Future = Either<
Box ) -> 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 ResourceEndpoint {
fn new(factory: Rc {
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(&())
}
}