1
0
Fork 0
mirror of https://github.com/actix/actix-web.git synced 2024-11-26 19:41:12 +00:00

use custom request for FromRequest trait

This commit is contained in:
Nikolay Kim 2019-03-02 19:19:56 -08:00
parent e4198a037a
commit 8103d33270
12 changed files with 342 additions and 216 deletions

View file

@ -2,7 +2,7 @@ use futures::IntoFuture;
use actix_http::{h1, http::Method, Response}; use actix_http::{h1, http::Method, Response};
use actix_server::Server; use actix_server::Server;
use actix_web::{middleware, App, Error, HttpRequest, Resource}; use actix_web::{middleware, web, App, Error, HttpRequest, Resource, Route};
fn index(req: HttpRequest) -> &'static str { fn index(req: HttpRequest) -> &'static str {
println!("REQ: {:?}", req); println!("REQ: {:?}", req);
@ -31,7 +31,7 @@ fn main() {
middleware::DefaultHeaders::new().header("X-Version", "0.2"), middleware::DefaultHeaders::new().header("X-Version", "0.2"),
) )
.middleware(middleware::Compress::default()) .middleware(middleware::Compress::default())
.resource("/resource1/index.html", |r| r.get(index)) .resource("/resource1/index.html", |r| r.route(web::get().to(index)))
.service( .service(
"/resource2/index.html", "/resource2/index.html",
Resource::new() Resource::new()
@ -39,8 +39,10 @@ fn main() {
middleware::DefaultHeaders::new() middleware::DefaultHeaders::new()
.header("X-Version-R2", "0.3"), .header("X-Version-R2", "0.3"),
) )
.default_resource(|r| r.to(|| Response::MethodNotAllowed())) .default_resource(|r| {
.method(Method::GET, |r| r.to_async(index_async)), r.route(Route::new().to(|| Response::MethodNotAllowed()))
})
.route(web::method(Method::GET).to_async(index_async)),
) )
.service("/test1.html", Resource::new().to(|| "Test\r\n")) .service("/test1.html", Resource::new().to(|| "Test\r\n"))
.service("/", Resource::new().to(no_params)), .service("/", Resource::new().to(no_params)),

View file

@ -159,16 +159,16 @@ where
} }
/// Register a middleware. /// Register a middleware.
pub fn middleware<M, F>( pub fn middleware<M, B, F>(
self, self,
mw: F, mw: F,
) -> AppRouter< ) -> AppRouter<
T, T,
P, P,
Body, B,
impl NewService< impl NewService<
Request = ServiceRequest<P>, Request = ServiceRequest<P>,
Response = ServiceResponse, Response = ServiceResponse<B>,
Error = (), Error = (),
InitError = (), InitError = (),
>, >,
@ -177,7 +177,7 @@ where
M: NewTransform< M: NewTransform<
AppService<P>, AppService<P>,
Request = ServiceRequest<P>, Request = ServiceRequest<P>,
Response = ServiceResponse, Response = ServiceResponse<B>,
Error = (), Error = (),
InitError = (), InitError = (),
>, >,

View file

@ -26,7 +26,7 @@ use actix_router::PathDeserializer;
use crate::handler::FromRequest; use crate::handler::FromRequest;
use crate::request::HttpRequest; use crate::request::HttpRequest;
use crate::responder::Responder; use crate::responder::Responder;
use crate::service::ServiceRequest; use crate::service::ServiceFromRequest;
#[derive(PartialEq, Eq, PartialOrd, Ord)] #[derive(PartialEq, Eq, PartialOrd, Ord)]
/// Extract typed information from the request's path. /// Extract typed information from the request's path.
@ -112,7 +112,7 @@ impl<T> Path<T> {
} }
/// Extract path information from a request /// Extract path information from a request
pub fn extract<P>(req: &ServiceRequest<P>) -> Result<Path<T>, de::value::Error> pub fn extract<P>(req: &ServiceFromRequest<P>) -> Result<Path<T>, de::value::Error>
where where
T: DeserializeOwned, T: DeserializeOwned,
{ {
@ -135,7 +135,7 @@ where
type Future = FutureResult<Self, Error>; type Future = FutureResult<Self, Error>;
#[inline] #[inline]
fn from_request(req: &mut ServiceRequest<P>) -> Self::Future { fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future {
Self::extract(req).map_err(ErrorNotFound).into_future() Self::extract(req).map_err(ErrorNotFound).into_future()
} }
} }
@ -221,7 +221,7 @@ where
type Future = FutureResult<Self, Error>; type Future = FutureResult<Self, Error>;
#[inline] #[inline]
fn from_request(req: &mut ServiceRequest<P>) -> Self::Future { fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future {
serde_urlencoded::from_str::<T>(req.query_string()) serde_urlencoded::from_str::<T>(req.query_string())
.map(|val| ok(Query(val))) .map(|val| ok(Query(val)))
.unwrap_or_else(|e| err(e.into())) .unwrap_or_else(|e| err(e.into()))
@ -301,7 +301,7 @@ where
type Future = Box<Future<Item = Self, Error = Error>>; type Future = Box<Future<Item = Self, Error = Error>>;
#[inline] #[inline]
fn from_request(req: &mut ServiceRequest<P>) -> Self::Future { fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future {
let cfg = FormConfig::default(); let cfg = FormConfig::default();
let req2 = req.clone(); let req2 = req.clone();
@ -511,7 +511,7 @@ where
type Future = Box<Future<Item = Self, Error = Error>>; type Future = Box<Future<Item = Self, Error = Error>>;
#[inline] #[inline]
fn from_request(req: &mut ServiceRequest<P>) -> Self::Future { fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future {
let cfg = JsonConfig::default(); let cfg = JsonConfig::default();
let req2 = req.clone(); let req2 = req.clone();
@ -619,7 +619,7 @@ where
Either<Box<Future<Item = Bytes, Error = Error>>, FutureResult<Bytes, Error>>; Either<Box<Future<Item = Bytes, Error = Error>>, FutureResult<Bytes, Error>>;
#[inline] #[inline]
fn from_request(req: &mut ServiceRequest<P>) -> Self::Future { fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future {
let cfg = PayloadConfig::default(); let cfg = PayloadConfig::default();
if let Err(e) = cfg.check_mimetype(req) { if let Err(e) = cfg.check_mimetype(req) {
@ -666,7 +666,7 @@ where
Either<Box<Future<Item = String, Error = Error>>, FutureResult<String, Error>>; Either<Box<Future<Item = String, Error = Error>>, FutureResult<String, Error>>;
#[inline] #[inline]
fn from_request(req: &mut ServiceRequest<P>) -> Self::Future { fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future {
let cfg = PayloadConfig::default(); let cfg = PayloadConfig::default();
// check content-type // check content-type
@ -755,7 +755,7 @@ where
type Future = Box<Future<Item = Option<T>, Error = Error>>; type Future = Box<Future<Item = Option<T>, Error = Error>>;
#[inline] #[inline]
fn from_request(req: &mut ServiceRequest<P>) -> Self::Future { fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future {
Box::new(T::from_request(req).then(|r| match r { Box::new(T::from_request(req).then(|r| match r {
Ok(v) => future::ok(Some(v)), Ok(v) => future::ok(Some(v)),
Err(_) => future::ok(None), Err(_) => future::ok(None),
@ -818,7 +818,7 @@ where
type Future = Box<Future<Item = Result<T, T::Error>, Error = Error>>; type Future = Box<Future<Item = Result<T, T::Error>, Error = Error>>;
#[inline] #[inline]
fn from_request(req: &mut ServiceRequest<P>) -> Self::Future { fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future {
Box::new(T::from_request(req).then(|res| match res { Box::new(T::from_request(req).then(|res| match res {
Ok(v) => ok(Ok(v)), Ok(v) => ok(Ok(v)),
Err(e) => ok(Err(e)), Err(e) => ok(Err(e)),
@ -846,7 +846,7 @@ impl PayloadConfig {
self self
} }
fn check_mimetype<P>(&self, req: &ServiceRequest<P>) -> Result<(), Error> { fn check_mimetype<P>(&self, req: &ServiceFromRequest<P>) -> Result<(), Error> {
// check content-type // check content-type
if let Some(ref mt) = self.mimetype { if let Some(ref mt) = self.mimetype {
match req.mime_type() { match req.mime_type() {
@ -884,7 +884,7 @@ macro_rules! tuple_from_req ({$fut_type:ident, $(($n:tt, $T:ident)),+} => {
type Error = Error; type Error = Error;
type Future = $fut_type<P, $($T),+>; type Future = $fut_type<P, $($T),+>;
fn from_request(req: &mut ServiceRequest<P>) -> Self::Future { fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future {
$fut_type { $fut_type {
items: <($(Option<$T>,)+)>::default(), items: <($(Option<$T>,)+)>::default(),
futs: ($($T::from_request(req),)+), futs: ($($T::from_request(req),)+),
@ -933,7 +933,7 @@ impl<P> FromRequest<P> for () {
type Error = Error; type Error = Error;
type Future = FutureResult<(), Error>; type Future = FutureResult<(), Error>;
fn from_request(_req: &mut ServiceRequest<P>) -> Self::Future { fn from_request(_req: &mut ServiceFromRequest<P>) -> Self::Future {
ok(()) ok(())
} }
} }

View file

@ -1,8 +1,7 @@
//! Route match predicates //! Route match predicates
#![allow(non_snake_case)] #![allow(non_snake_case)]
use actix_http::http::{self, header, HttpTryFrom}; use actix_http::http::{self, header, HttpTryFrom};
use actix_http::RequestHead;
use crate::request::HttpRequest;
/// Trait defines resource predicate. /// Trait defines resource predicate.
/// Predicate can modify request object. It is also possible to /// Predicate can modify request object. It is also possible to
@ -10,20 +9,21 @@ use crate::request::HttpRequest;
/// Extensions container available via `HttpRequest::extensions()` method. /// Extensions container available via `HttpRequest::extensions()` method.
pub trait Filter { pub trait Filter {
/// Check if request matches predicate /// Check if request matches predicate
fn check(&self, request: &HttpRequest) -> bool; fn check(&self, request: &RequestHead) -> bool;
} }
/// Return filter that matches if any of supplied filters. /// Return filter that matches if any of supplied filters.
/// ///
/// ```rust,ignore /// ```rust
/// use actix_web::{filter, App, HttpResponse}; /// use actix_web::{web, filter, App, HttpResponse};
/// ///
/// fn main() { /// fn main() {
/// App::new().resource("/index.html", |r| { /// App::new().resource("/index.html", |r|
/// r.route() /// r.route(
/// .filter(pred::Any(pred::Get()).or(pred::Post())) /// web::route()
/// .to(|| HttpResponse::MethodNotAllowed()) /// .filter(filter::Any(filter::Get()).or(filter::Post()))
/// }); /// .to(|| HttpResponse::MethodNotAllowed()))
/// );
/// } /// }
/// ``` /// ```
pub fn Any<F: Filter + 'static>(filter: F) -> AnyFilter { pub fn Any<F: Filter + 'static>(filter: F) -> AnyFilter {
@ -42,7 +42,7 @@ impl AnyFilter {
} }
impl Filter for AnyFilter { impl Filter for AnyFilter {
fn check(&self, req: &HttpRequest) -> bool { fn check(&self, req: &RequestHead) -> bool {
for p in &self.0 { for p in &self.0 {
if p.check(req) { if p.check(req) {
return true; return true;
@ -56,15 +56,13 @@ impl Filter for AnyFilter {
/// ///
/// ```rust /// ```rust
/// # extern crate actix_web; /// # extern crate actix_web;
/// use actix_web::{filter, App, HttpResponse}; /// use actix_web::{filter, web, App, HttpResponse};
/// ///
/// fn main() { /// fn main() {
/// App::new().resource("/index.html", |r| { /// App::new().resource("/index.html", |r| {
/// r.route( /// r.route(web::route()
/// |r| r.filter( /// .filter(
/// filter::All(filter::Get()) /// filter::All(filter::Get()).and(filter::Header("content-type", "text/plain")))
/// .and(filter::Header("content-type", "text/plain")),
/// )
/// .to(|| HttpResponse::MethodNotAllowed())) /// .to(|| HttpResponse::MethodNotAllowed()))
/// }); /// });
/// } /// }
@ -85,7 +83,7 @@ impl AllFilter {
} }
impl Filter for AllFilter { impl Filter for AllFilter {
fn check(&self, request: &HttpRequest) -> bool { fn check(&self, request: &RequestHead) -> bool {
for p in &self.0 { for p in &self.0 {
if !p.check(request) { if !p.check(request) {
return false; return false;
@ -104,7 +102,7 @@ pub fn Not<F: Filter + 'static>(filter: F) -> NotFilter {
pub struct NotFilter(Box<Filter>); pub struct NotFilter(Box<Filter>);
impl Filter for NotFilter { impl Filter for NotFilter {
fn check(&self, request: &HttpRequest) -> bool { fn check(&self, request: &RequestHead) -> bool {
!self.0.check(request) !self.0.check(request)
} }
} }
@ -114,8 +112,8 @@ impl Filter for NotFilter {
pub struct MethodFilter(http::Method); pub struct MethodFilter(http::Method);
impl Filter for MethodFilter { impl Filter for MethodFilter {
fn check(&self, request: &HttpRequest) -> bool { fn check(&self, request: &RequestHead) -> bool {
request.method() == self.0 request.method == self.0
} }
} }
@ -182,8 +180,8 @@ pub fn Header(name: &'static str, value: &'static str) -> HeaderFilter {
pub struct HeaderFilter(header::HeaderName, header::HeaderValue); pub struct HeaderFilter(header::HeaderName, header::HeaderValue);
impl Filter for HeaderFilter { impl Filter for HeaderFilter {
fn check(&self, req: &HttpRequest) -> bool { fn check(&self, req: &RequestHead) -> bool {
if let Some(val) = req.headers().get(&self.0) { if let Some(val) = req.headers.get(&self.0) {
return val == self.1; return val == self.1;
} }
false false
@ -219,7 +217,7 @@ impl Filter for HeaderFilter {
// } // }
// impl Filter for HostFilter { // impl Filter for HostFilter {
// fn check(&self, _req: &HttpRequest) -> bool { // fn check(&self, _req: &RequestHead) -> bool {
// // let info = req.connection_info(); // // let info = req.connection_info();
// // if let Some(ref scheme) = self.1 { // // if let Some(ref scheme) = self.1 {
// // self.0 == info.host() && scheme == info.scheme() // // self.0 == info.host() && scheme == info.scheme()

View file

@ -7,7 +7,7 @@ use futures::{try_ready, Async, Future, IntoFuture, Poll};
use crate::request::HttpRequest; use crate::request::HttpRequest;
use crate::responder::Responder; use crate::responder::Responder;
use crate::service::{ServiceRequest, ServiceResponse}; use crate::service::{ServiceFromRequest, ServiceRequest, ServiceResponse};
/// Trait implemented by types that can be extracted from request. /// Trait implemented by types that can be extracted from request.
/// ///
@ -20,7 +20,7 @@ pub trait FromRequest<P>: Sized {
type Future: Future<Item = Self, Error = Self::Error>; type Future: Future<Item = Self, Error = Self::Error>;
/// Convert request to a Self /// Convert request to a Self
fn from_request(req: &mut ServiceRequest<P>) -> Self::Future; fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future;
} }
/// Handler converter factory /// Handler converter factory
@ -306,7 +306,7 @@ impl<P, T: FromRequest<P>> Default for Extract<P, T> {
impl<P, T: FromRequest<P>> NewService for Extract<P, T> { impl<P, T: FromRequest<P>> NewService for Extract<P, T> {
type Request = ServiceRequest<P>; type Request = ServiceRequest<P>;
type Response = (T, HttpRequest); type Response = (T, HttpRequest);
type Error = (Error, ServiceRequest<P>); type Error = (Error, ServiceFromRequest<P>);
type InitError = (); type InitError = ();
type Service = ExtractService<P, T>; type Service = ExtractService<P, T>;
type Future = FutureResult<Self::Service, ()>; type Future = FutureResult<Self::Service, ()>;
@ -323,14 +323,15 @@ pub struct ExtractService<P, T: FromRequest<P>> {
impl<P, T: FromRequest<P>> Service for ExtractService<P, T> { impl<P, T: FromRequest<P>> Service for ExtractService<P, T> {
type Request = ServiceRequest<P>; type Request = ServiceRequest<P>;
type Response = (T, HttpRequest); type Response = (T, HttpRequest);
type Error = (Error, ServiceRequest<P>); type Error = (Error, ServiceFromRequest<P>);
type Future = ExtractResponse<P, T>; type Future = ExtractResponse<P, T>;
fn poll_ready(&mut self) -> Poll<(), Self::Error> { fn poll_ready(&mut self) -> Poll<(), Self::Error> {
Ok(Async::Ready(())) Ok(Async::Ready(()))
} }
fn call(&mut self, mut req: ServiceRequest<P>) -> Self::Future { fn call(&mut self, req: ServiceRequest<P>) -> Self::Future {
let mut req = req.into();
ExtractResponse { ExtractResponse {
fut: T::from_request(&mut req), fut: T::from_request(&mut req),
req: Some(req), req: Some(req),
@ -339,13 +340,13 @@ impl<P, T: FromRequest<P>> Service for ExtractService<P, T> {
} }
pub struct ExtractResponse<P, T: FromRequest<P>> { pub struct ExtractResponse<P, T: FromRequest<P>> {
req: Option<ServiceRequest<P>>, req: Option<ServiceFromRequest<P>>,
fut: T::Future, fut: T::Future,
} }
impl<P, T: FromRequest<P>> Future for ExtractResponse<P, T> { impl<P, T: FromRequest<P>> Future for ExtractResponse<P, T> {
type Item = (T, HttpRequest); type Item = (T, HttpRequest);
type Error = (Error, ServiceRequest<P>); type Error = (Error, ServiceFromRequest<P>);
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
let item = try_ready!(self let item = try_ready!(self

View file

@ -25,12 +25,91 @@ pub use crate::handler::FromRequest;
pub use crate::request::HttpRequest; pub use crate::request::HttpRequest;
pub use crate::resource::Resource; pub use crate::resource::Resource;
pub use crate::responder::{Either, Responder}; pub use crate::responder::{Either, Responder};
pub use crate::route::Route;
pub use crate::service::{ServiceRequest, ServiceResponse}; pub use crate::service::{ServiceRequest, ServiceResponse};
pub use crate::state::State; pub use crate::state::State;
pub mod web {
use actix_http::{http::Method, Error, Response};
use futures::IntoFuture;
use crate::handler::{AsyncFactory, Factory, FromRequest};
use crate::responder::Responder;
use crate::Route;
pub fn route<P: 'static>() -> Route<P> {
Route::new()
}
pub fn get<P: 'static>() -> Route<P> {
Route::get()
}
pub fn post<P: 'static>() -> Route<P> {
Route::post()
}
pub fn put<P: 'static>() -> Route<P> {
Route::put()
}
pub fn delete<P: 'static>() -> Route<P> {
Route::delete()
}
pub fn head<P: 'static>() -> Route<P> {
Route::new().method(Method::HEAD)
}
pub fn method<P: 'static>(method: Method) -> Route<P> {
Route::new().method(method)
}
/// Create a new route and add handler.
///
/// ```rust
/// use actix_web::{web, App, HttpResponse};
///
/// fn index() -> HttpResponse {
/// unimplemented!()
/// }
///
/// App::new().resource("/", |r| r.route(web::to(index)));
/// ```
pub fn to<F, I, R, P: 'static>(handler: F) -> Route<P>
where
F: Factory<I, R> + 'static,
I: FromRequest<P> + 'static,
R: Responder + 'static,
{
Route::new().to(handler)
}
/// Create a new route and add async handler.
///
/// ```rust
/// use actix_web::{web, App, HttpResponse, Error};
///
/// fn index() -> impl futures::Future<Item=HttpResponse, Error=Error> {
/// futures::future::ok(HttpResponse::Ok().finish())
/// }
///
/// App::new().resource("/", |r| r.route(web::to_async(index)));
/// ```
pub fn to_async<F, I, R, P: 'static>(handler: F) -> Route<P>
where
F: AsyncFactory<I, R>,
I: FromRequest<P> + 'static,
R: IntoFuture + 'static,
R::Item: Into<Response>,
R::Error: Into<Error>,
{
Route::new().to_async(handler)
}
}
pub mod dev { pub mod dev {
pub use crate::app::AppRouter; pub use crate::app::AppRouter;
pub use crate::handler::{AsyncFactory, Extract, Factory, Handle}; pub use crate::handler::{AsyncFactory, Extract, Factory, Handle};
pub use crate::route::{Route, RouteBuilder};
// pub use crate::info::ConnectionInfo; // pub use crate::info::ConnectionInfo;
} }

View file

@ -9,11 +9,11 @@ use actix_router::{Path, Url};
use futures::future::{ok, FutureResult}; use futures::future::{ok, FutureResult};
use crate::handler::FromRequest; use crate::handler::FromRequest;
use crate::service::ServiceRequest; use crate::service::ServiceFromRequest;
#[derive(Clone)] #[derive(Clone)]
pub struct HttpRequest { pub struct HttpRequest {
head: Message<RequestHead>, pub(crate) head: Message<RequestHead>,
pub(crate) path: Path<Url>, pub(crate) path: Path<Url>,
extensions: Rc<Extensions>, extensions: Rc<Extensions>,
} }
@ -145,7 +145,7 @@ impl<P> FromRequest<P> for HttpRequest {
type Future = FutureResult<Self, Error>; type Future = FutureResult<Self, Error>;
#[inline] #[inline]
fn from_request(req: &mut ServiceRequest<P>) -> Self::Future { fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future {
ok(req.clone()) ok(req.clone())
} }
} }

View file

@ -1,7 +1,7 @@
use std::cell::RefCell; use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
use actix_http::{http::Method, Error, Response}; use actix_http::{Error, Response};
use actix_service::boxed::{self, BoxedNewService, BoxedService}; use actix_service::boxed::{self, BoxedNewService, BoxedService};
use actix_service::{ use actix_service::{
ApplyNewService, IntoNewService, IntoNewTransform, NewService, NewTransform, Service, ApplyNewService, IntoNewService, IntoNewTransform, NewService, NewTransform, Service,
@ -11,7 +11,7 @@ use futures::{Async, Future, IntoFuture, Poll};
use crate::handler::{AsyncFactory, Factory, FromRequest}; use crate::handler::{AsyncFactory, Factory, FromRequest};
use crate::responder::Responder; use crate::responder::Responder;
use crate::route::{CreateRouteService, Route, RouteBuilder, RouteService}; use crate::route::{CreateRouteService, Route, RouteService};
use crate::service::{ServiceRequest, ServiceResponse}; use crate::service::{ServiceRequest, ServiceResponse};
type HttpService<P> = BoxedService<ServiceRequest<P>, ServiceResponse, ()>; type HttpService<P> = BoxedService<ServiceRequest<P>, ServiceResponse, ()>;
@ -74,92 +74,8 @@ where
/// .finish(); /// .finish();
/// } /// }
/// ``` /// ```
pub fn route<F>(mut self, f: F) -> Self pub fn route(mut self, route: Route<P>) -> Self {
where self.routes.push(route);
F: FnOnce(RouteBuilder<P>) -> Route<P>,
{
self.routes.push(f(Route::build()));
self
}
/// Register a new `GET` route.
pub fn get<F, I, R>(mut self, f: F) -> Self
where
F: Factory<I, R> + 'static,
I: FromRequest<P> + 'static,
R: Responder + 'static,
{
self.routes.push(Route::get().to(f));
self
}
/// Register a new `POST` route.
pub fn post<F, I, R>(mut self, f: F) -> Self
where
F: Factory<I, R> + 'static,
I: FromRequest<P> + 'static,
R: Responder + 'static,
{
self.routes.push(Route::post().to(f));
self
}
/// Register a new `PUT` route.
pub fn put<F, I, R>(mut self, f: F) -> Self
where
F: Factory<I, R> + 'static,
I: FromRequest<P> + 'static,
R: Responder + 'static,
{
self.routes.push(Route::put().to(f));
self
}
/// Register a new `DELETE` route.
pub fn delete<F, I, R>(mut self, f: F) -> Self
where
F: Factory<I, R> + 'static,
I: FromRequest<P> + 'static,
R: Responder + 'static,
{
self.routes.push(Route::delete().to(f));
self
}
/// Register a new `HEAD` route.
pub fn head<F, I, R>(mut self, f: F) -> Self
where
F: Factory<I, R> + 'static,
I: FromRequest<P> + '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<F>(mut self, method: Method, f: F) -> Self
where
F: FnOnce(RouteBuilder<P>) -> Route<P>,
{
self.routes.push(f(Route::build().method(method)));
self self
} }
@ -187,7 +103,7 @@ where
I: FromRequest<P> + 'static, I: FromRequest<P> + 'static,
R: Responder + 'static, R: Responder + 'static,
{ {
self.routes.push(Route::build().to(handler)); self.routes.push(Route::new().to(handler));
self self
} }
@ -227,7 +143,7 @@ where
R::Item: Into<Response>, R::Item: Into<Response>,
R::Error: Into<Error>, R::Error: Into<Error>,
{ {
self.routes.push(Route::build().to_async(handler)); self.routes.push(Route::new().to_async(handler));
self self
} }

View file

@ -1,4 +1,3 @@
use std::marker::PhantomData;
use std::rc::Rc; use std::rc::Rc;
use actix_http::{http::Method, Error, Response}; use actix_http::{http::Method, Error, Response};
@ -8,7 +7,8 @@ use futures::{Async, Future, IntoFuture, Poll};
use crate::filter::{self, Filter}; use crate::filter::{self, Filter};
use crate::handler::{AsyncFactory, AsyncHandle, Extract, Factory, FromRequest, Handle}; use crate::handler::{AsyncFactory, AsyncHandle, Extract, Factory, FromRequest, Handle};
use crate::responder::Responder; use crate::responder::Responder;
use crate::service::{ServiceRequest, ServiceResponse}; use crate::service::{ServiceFromRequest, ServiceRequest, ServiceResponse};
use crate::HttpResponse;
type BoxedRouteService<Req, Res> = Box< type BoxedRouteService<Req, Res> = Box<
Service< Service<
@ -40,24 +40,29 @@ pub struct Route<P> {
} }
impl<P: 'static> Route<P> { impl<P: 'static> Route<P> {
pub fn build() -> RouteBuilder<P> { pub fn new() -> Route<P> {
RouteBuilder::new() Route {
service: Box::new(RouteNewService::new(Extract::new().and_then(
Handle::new(|| HttpResponse::NotFound()).map_err(|_| panic!()),
))),
filters: Rc::new(Vec::new()),
}
} }
pub fn get() -> RouteBuilder<P> { pub fn get() -> Route<P> {
RouteBuilder::new().method(Method::GET) Route::new().method(Method::GET)
} }
pub fn post() -> RouteBuilder<P> { pub fn post() -> Route<P> {
RouteBuilder::new().method(Method::POST) Route::new().method(Method::POST)
} }
pub fn put() -> RouteBuilder<P> { pub fn put() -> Route<P> {
RouteBuilder::new().method(Method::PUT) Route::new().method(Method::PUT)
} }
pub fn delete() -> RouteBuilder<P> { pub fn delete() -> Route<P> {
RouteBuilder::new().method(Method::DELETE) Route::new().method(Method::DELETE)
} }
} }
@ -109,7 +114,7 @@ pub struct RouteService<P> {
impl<P> RouteService<P> { impl<P> RouteService<P> {
pub fn check(&self, req: &mut ServiceRequest<P>) -> bool { pub fn check(&self, req: &mut ServiceRequest<P>) -> bool {
for f in self.filters.iter() { for f in self.filters.iter() {
if !f.check(req.request()) { if !f.check(req.head()) {
return false; return false;
} }
} }
@ -132,19 +137,7 @@ impl<P> Service for RouteService<P> {
} }
} }
pub struct RouteBuilder<P> { impl<P: 'static> Route<P> {
filters: Vec<Box<Filter>>,
_t: PhantomData<P>,
}
impl<P: 'static> RouteBuilder<P> {
fn new() -> RouteBuilder<P> {
RouteBuilder {
filters: Vec::new(),
_t: PhantomData,
}
}
/// Add method match filter to the route. /// Add method match filter to the route.
/// ///
/// ```rust,ignore /// ```rust,ignore
@ -161,7 +154,9 @@ impl<P: 'static> RouteBuilder<P> {
/// # } /// # }
/// ``` /// ```
pub fn method(mut self, method: Method) -> Self { pub fn method(mut self, method: Method) -> Self {
self.filters.push(Box::new(filter::Method(method))); Rc::get_mut(&mut self.filters)
.unwrap()
.push(Box::new(filter::Method(method)));
self self
} }
@ -181,7 +176,7 @@ impl<P: 'static> RouteBuilder<P> {
/// # } /// # }
/// ``` /// ```
pub fn filter<F: Filter + 'static>(mut self, f: F) -> Self { pub fn filter<F: Filter + 'static>(mut self, f: F) -> Self {
self.filters.push(Box::new(f)); Rc::get_mut(&mut self.filters).unwrap().push(Box::new(f));
self self
} }
@ -259,18 +254,16 @@ impl<P: 'static> RouteBuilder<P> {
/// ); // <- use `with` extractor /// ); // <- use `with` extractor
/// } /// }
/// ``` /// ```
pub fn to<F, T, R>(self, handler: F) -> Route<P> pub fn to<F, T, R>(mut self, handler: F) -> Route<P>
where where
F: Factory<T, R> + 'static, F: Factory<T, R> + 'static,
T: FromRequest<P> + 'static, T: FromRequest<P> + 'static,
R: Responder + 'static, R: Responder + 'static,
{ {
Route { self.service = Box::new(RouteNewService::new(
service: Box::new(RouteNewService::new(
Extract::new().and_then(Handle::new(handler).map_err(|_| panic!())), Extract::new().and_then(Handle::new(handler).map_err(|_| panic!())),
)), ));
filters: Rc::new(self.filters), self
}
} }
/// Set async handler function, use request extractor for parameters. /// Set async handler function, use request extractor for parameters.
@ -303,7 +296,7 @@ impl<P: 'static> RouteBuilder<P> {
/// } /// }
/// ``` /// ```
#[allow(clippy::wrong_self_convention)] #[allow(clippy::wrong_self_convention)]
pub fn to_async<F, T, R>(self, handler: F) -> Route<P> pub fn to_async<F, T, R>(mut self, handler: F) -> Self
where where
F: AsyncFactory<T, R>, F: AsyncFactory<T, R>,
T: FromRequest<P> + 'static, T: FromRequest<P> + 'static,
@ -311,12 +304,10 @@ impl<P: 'static> RouteBuilder<P> {
R::Item: Into<Response>, R::Item: Into<Response>,
R::Error: Into<Error>, R::Error: Into<Error>,
{ {
Route { self.service = Box::new(RouteNewService::new(
service: Box::new(RouteNewService::new(
Extract::new().and_then(AsyncHandle::new(handler).map_err(|_| panic!())), Extract::new().and_then(AsyncHandle::new(handler).map_err(|_| panic!())),
)), ));
filters: Rc::new(self.filters), self
}
} }
} }
@ -450,7 +441,7 @@ impl<P: 'static> RouteBuilder<P> {
struct RouteNewService<P, T> struct RouteNewService<P, T>
where where
T: NewService<Request = ServiceRequest<P>, Error = (Error, ServiceRequest<P>)>, T: NewService<Request = ServiceRequest<P>, Error = (Error, ServiceFromRequest<P>)>,
{ {
service: T, service: T,
} }
@ -460,7 +451,7 @@ where
T: NewService< T: NewService<
Request = ServiceRequest<P>, Request = ServiceRequest<P>,
Response = ServiceResponse, Response = ServiceResponse,
Error = (Error, ServiceRequest<P>), Error = (Error, ServiceFromRequest<P>),
>, >,
T::Future: 'static, T::Future: 'static,
T::Service: 'static, T::Service: 'static,
@ -476,7 +467,7 @@ where
T: NewService< T: NewService<
Request = ServiceRequest<P>, Request = ServiceRequest<P>,
Response = ServiceResponse, Response = ServiceResponse,
Error = (Error, ServiceRequest<P>), Error = (Error, ServiceFromRequest<P>),
>, >,
T::Future: 'static, T::Future: 'static,
T::Service: 'static, T::Service: 'static,
@ -513,7 +504,7 @@ where
T: Service< T: Service<
Request = ServiceRequest<P>, Request = ServiceRequest<P>,
Response = ServiceResponse, Response = ServiceResponse,
Error = (Error, ServiceRequest<P>), Error = (Error, ServiceFromRequest<P>),
>, >,
{ {
type Request = ServiceRequest<P>; type Request = ServiceRequest<P>;

View file

@ -1,9 +1,11 @@
use std::cell::{Ref, RefMut};
use std::rc::Rc; use std::rc::Rc;
use actix_http::body::{Body, MessageBody, ResponseBody}; use actix_http::body::{Body, MessageBody, ResponseBody};
use actix_http::http::HeaderMap; use actix_http::http::{HeaderMap, Method, Uri, Version};
use actix_http::{ use actix_http::{
Error, Extensions, HttpMessage, Payload, Request, Response, ResponseHead, Error, Extensions, HttpMessage, Payload, Request, RequestHead, Response,
ResponseHead,
}; };
use actix_router::{Path, Url}; use actix_router::{Path, Url};
@ -27,11 +29,6 @@ impl<P> ServiceRequest<P> {
} }
} }
#[inline]
pub fn request(&self) -> &HttpRequest {
&self.req
}
#[inline] #[inline]
pub fn into_request(self) -> HttpRequest { pub fn into_request(self) -> HttpRequest {
self.req self.req
@ -49,10 +46,93 @@ impl<P> ServiceRequest<P> {
ServiceResponse::new(self.req, err.into().into()) ServiceResponse::new(self.req, err.into().into())
} }
/// This method returns reference to the request head
#[inline]
pub fn head(&self) -> &RequestHead {
&self.req.head
}
/// This method returns reference to the request head
#[inline]
pub fn head_mut(&mut self) -> &mut RequestHead {
&mut self.req.head
}
/// Request's uri.
#[inline]
pub fn uri(&self) -> &Uri {
&self.head().uri
}
/// Read the Request method.
#[inline]
pub fn method(&self) -> &Method {
&self.head().method
}
/// Read the Request Version.
#[inline]
pub fn version(&self) -> Version {
self.head().version
}
/// The target path of this Request.
#[inline]
pub fn path(&self) -> &str {
self.head().uri.path()
}
#[inline]
/// Returns Request's headers.
pub fn headers(&self) -> &HeaderMap {
&self.head().headers
}
/// The query string in the URL.
///
/// E.g., id=10
#[inline]
pub fn query_string(&self) -> &str {
if let Some(query) = self.uri().query().as_ref() {
query
} else {
""
}
}
/// Get a reference to the Path parameters.
///
/// Params is a container for url parameters.
/// A variable segment is specified in the form `{identifier}`,
/// where the identifier can be used later in a request handler to
/// access the matched value for that segment.
#[inline]
pub fn match_info(&self) -> &Path<Url> {
&self.req.path
}
#[inline] #[inline]
pub fn match_info_mut(&mut self) -> &mut Path<Url> { pub fn match_info_mut(&mut self) -> &mut Path<Url> {
&mut self.req.path &mut self.req.path
} }
/// Request extensions
#[inline]
pub fn extensions(&self) -> Ref<Extensions> {
self.req.head.extensions()
}
/// Mutable reference to a the request's extensions
#[inline]
pub fn extensions_mut(&self) -> RefMut<Extensions> {
self.req.head.extensions_mut()
}
/// Application extensions
#[inline]
pub fn app_extensions(&self) -> &Extensions {
self.req.app_extensions()
}
} }
impl<P> HttpMessage for ServiceRequest<P> { impl<P> HttpMessage for ServiceRequest<P> {
@ -70,10 +150,65 @@ impl<P> HttpMessage for ServiceRequest<P> {
} }
impl<P> std::ops::Deref for ServiceRequest<P> { impl<P> std::ops::Deref for ServiceRequest<P> {
type Target = RequestHead;
fn deref(&self) -> &RequestHead {
self.req.head()
}
}
impl<P> std::ops::DerefMut for ServiceRequest<P> {
fn deref_mut(&mut self) -> &mut RequestHead {
self.head_mut()
}
}
pub struct ServiceFromRequest<P> {
req: HttpRequest,
payload: Payload<P>,
}
impl<P> ServiceFromRequest<P> {
#[inline]
pub fn into_request(self) -> HttpRequest {
self.req
}
/// Create service response for error
#[inline]
pub fn error_response<E: Into<Error>>(self, err: E) -> ServiceResponse {
ServiceResponse::new(self.req, err.into().into())
}
}
impl<P> std::ops::Deref for ServiceFromRequest<P> {
type Target = HttpRequest; type Target = HttpRequest;
fn deref(&self) -> &HttpRequest { fn deref(&self) -> &HttpRequest {
self.request() &self.req
}
}
impl<P> HttpMessage for ServiceFromRequest<P> {
type Stream = P;
#[inline]
fn headers(&self) -> &HeaderMap {
self.req.headers()
}
#[inline]
fn take_payload(&mut self) -> Payload<Self::Stream> {
std::mem::replace(&mut self.payload, Payload::None)
}
}
impl<P> From<ServiceRequest<P>> for ServiceFromRequest<P> {
fn from(req: ServiceRequest<P>) -> Self {
Self {
req: req.req,
payload: req.payload,
}
} }
} }

View file

@ -7,7 +7,7 @@ use futures::future::{err, ok, FutureResult};
use futures::{Async, Future, IntoFuture, Poll}; use futures::{Async, Future, IntoFuture, Poll};
use crate::handler::FromRequest; use crate::handler::FromRequest;
use crate::service::ServiceRequest; use crate::service::ServiceFromRequest;
/// Application state factory /// Application state factory
pub(crate) trait StateFactory { pub(crate) trait StateFactory {
@ -50,7 +50,7 @@ impl<S: 'static, P> FromRequest<P> for State<S> {
type Future = FutureResult<Self, Error>; type Future = FutureResult<Self, Error>;
#[inline] #[inline]
fn from_request(req: &mut ServiceRequest<P>) -> Self::Future { fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future {
if let Some(st) = req.app_extensions().get::<State<S>>() { if let Some(st) = req.app_extensions().get::<State<S>>() {
ok(st.clone()) ok(st.clone())
} else { } else {

View file

@ -12,7 +12,7 @@ use flate2::write::ZlibDecoder;
use futures::stream::once; //Future, Stream use futures::stream::once; //Future, Stream
use rand::{distributions::Alphanumeric, Rng}; use rand::{distributions::Alphanumeric, Rng};
use actix_web::{middleware, App}; use actix_web::{middleware, web, App};
const STR: &str = "Hello World Hello World Hello World Hello World Hello World \ const STR: &str = "Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \ Hello World Hello World Hello World Hello World Hello World \
@ -40,7 +40,7 @@ const STR: &str = "Hello World Hello World Hello World Hello World Hello World \
fn test_body() { fn test_body() {
let mut srv = TestServer::new(|| { let mut srv = TestServer::new(|| {
h1::H1Service::new( h1::H1Service::new(
App::new().resource("/", |r| r.get(|| Response::Ok().body(STR))), App::new().resource("/", |r| r.route(web::to(|| Response::Ok().body(STR)))),
) )
}); });
@ -59,7 +59,7 @@ fn test_body_gzip() {
h1::H1Service::new( h1::H1Service::new(
App::new() App::new()
.middleware(middleware::Compress::new(ContentEncoding::Gzip)) .middleware(middleware::Compress::new(ContentEncoding::Gzip))
.resource("/", |r| r.get(|| Response::Ok().body(STR))), .resource("/", |r| r.route(web::to(|| Response::Ok().body(STR)))),
) )
}); });
@ -87,7 +87,9 @@ fn test_body_gzip_large() {
h1::H1Service::new( h1::H1Service::new(
App::new() App::new()
.middleware(middleware::Compress::new(ContentEncoding::Gzip)) .middleware(middleware::Compress::new(ContentEncoding::Gzip))
.resource("/", |r| r.get(move || Response::Ok().body(data.clone()))), .resource("/", |r| {
r.route(web::to(move || Response::Ok().body(data.clone())))
}),
) )
}); });
@ -118,7 +120,9 @@ fn test_body_gzip_large_random() {
h1::H1Service::new( h1::H1Service::new(
App::new() App::new()
.middleware(middleware::Compress::new(ContentEncoding::Gzip)) .middleware(middleware::Compress::new(ContentEncoding::Gzip))
.resource("/", |r| r.get(move || Response::Ok().body(data.clone()))), .resource("/", |r| {
r.route(web::to(move || Response::Ok().body(data.clone())))
}),
) )
}); });
@ -144,11 +148,11 @@ fn test_body_chunked_implicit() {
App::new() App::new()
.middleware(middleware::Compress::new(ContentEncoding::Gzip)) .middleware(middleware::Compress::new(ContentEncoding::Gzip))
.resource("/", |r| { .resource("/", |r| {
r.get(move || { r.route(web::get().to(move || {
Response::Ok().streaming(once(Ok::<_, Error>( Response::Ok().streaming(once(Ok::<_, Error>(
Bytes::from_static(STR.as_ref()), Bytes::from_static(STR.as_ref()),
))) )))
}) }))
}), }),
) )
}); });
@ -178,11 +182,11 @@ fn test_body_br_streaming() {
App::new() App::new()
.middleware(middleware::Compress::new(ContentEncoding::Br)) .middleware(middleware::Compress::new(ContentEncoding::Br))
.resource("/", |r| { .resource("/", |r| {
r.get(move || { r.route(web::to(move || {
Response::Ok().streaming(once(Ok::<_, Error>( Response::Ok().streaming(once(Ok::<_, Error>(
Bytes::from_static(STR.as_ref()), Bytes::from_static(STR.as_ref()),
))) )))
}) }))
}), }),
) )
}); });
@ -205,7 +209,7 @@ fn test_body_br_streaming() {
fn test_head_binary() { fn test_head_binary() {
let mut srv = TestServer::new(move || { let mut srv = TestServer::new(move || {
h1::H1Service::new(App::new().resource("/", |r| { h1::H1Service::new(App::new().resource("/", |r| {
r.head(move || Response::Ok().content_length(100).body(STR)) r.route(web::head().to(move || Response::Ok().content_length(100).body(STR)))
})) }))
}); });
@ -227,12 +231,12 @@ fn test_head_binary() {
fn test_no_chunking() { fn test_no_chunking() {
let mut srv = TestServer::new(move || { let mut srv = TestServer::new(move || {
h1::H1Service::new(App::new().resource("/", |r| { h1::H1Service::new(App::new().resource("/", |r| {
r.get(move || { r.route(web::to(move || {
Response::Ok() Response::Ok()
.no_chunking() .no_chunking()
.content_length(STR.len() as u64) .content_length(STR.len() as u64)
.streaming(once(Ok::<_, Error>(Bytes::from_static(STR.as_ref())))) .streaming(once(Ok::<_, Error>(Bytes::from_static(STR.as_ref()))))
}) }))
})) }))
}); });
@ -252,7 +256,7 @@ fn test_body_deflate() {
h1::H1Service::new( h1::H1Service::new(
App::new() App::new()
.middleware(middleware::Compress::new(ContentEncoding::Deflate)) .middleware(middleware::Compress::new(ContentEncoding::Deflate))
.resource("/", |r| r.get(move || Response::Ok().body(STR))), .resource("/", |r| r.route(web::to(move || Response::Ok().body(STR)))),
) )
}); });
@ -277,7 +281,7 @@ fn test_body_brotli() {
h1::H1Service::new( h1::H1Service::new(
App::new() App::new()
.middleware(middleware::Compress::new(ContentEncoding::Br)) .middleware(middleware::Compress::new(ContentEncoding::Br))
.resource("/", |r| r.get(move || Response::Ok().body(STR))), .resource("/", |r| r.route(web::to(move || Response::Ok().body(STR)))),
) )
}); });