1
0
Fork 0
mirror of https://github.com/actix/actix-web.git synced 2024-06-10 17:29:36 +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_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 {
println!("REQ: {:?}", req);
@ -31,7 +31,7 @@ fn main() {
middleware::DefaultHeaders::new().header("X-Version", "0.2"),
)
.middleware(middleware::Compress::default())
.resource("/resource1/index.html", |r| r.get(index))
.resource("/resource1/index.html", |r| r.route(web::get().to(index)))
.service(
"/resource2/index.html",
Resource::new()
@ -39,8 +39,10 @@ fn main() {
middleware::DefaultHeaders::new()
.header("X-Version-R2", "0.3"),
)
.default_resource(|r| r.to(|| Response::MethodNotAllowed()))
.method(Method::GET, |r| r.to_async(index_async)),
.default_resource(|r| {
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("/", Resource::new().to(no_params)),

View file

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

View file

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

View file

@ -1,8 +1,7 @@
//! Route match predicates
#![allow(non_snake_case)]
use actix_http::http::{self, header, HttpTryFrom};
use crate::request::HttpRequest;
use actix_http::RequestHead;
/// Trait defines resource predicate.
/// 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.
pub trait Filter {
/// 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.
///
/// ```rust,ignore
/// use actix_web::{filter, App, HttpResponse};
/// ```rust
/// use actix_web::{web, filter, App, HttpResponse};
///
/// fn main() {
/// App::new().resource("/index.html", |r| {
/// r.route()
/// .filter(pred::Any(pred::Get()).or(pred::Post()))
/// .to(|| HttpResponse::MethodNotAllowed())
/// });
/// App::new().resource("/index.html", |r|
/// r.route(
/// web::route()
/// .filter(filter::Any(filter::Get()).or(filter::Post()))
/// .to(|| HttpResponse::MethodNotAllowed()))
/// );
/// }
/// ```
pub fn Any<F: Filter + 'static>(filter: F) -> AnyFilter {
@ -42,7 +42,7 @@ impl AnyFilter {
}
impl Filter for AnyFilter {
fn check(&self, req: &HttpRequest) -> bool {
fn check(&self, req: &RequestHead) -> bool {
for p in &self.0 {
if p.check(req) {
return true;
@ -56,15 +56,13 @@ impl Filter for AnyFilter {
///
/// ```rust
/// # extern crate actix_web;
/// use actix_web::{filter, App, HttpResponse};
/// use actix_web::{filter, web, App, HttpResponse};
///
/// fn main() {
/// App::new().resource("/index.html", |r| {
/// r.route(
/// |r| r.filter(
/// filter::All(filter::Get())
/// .and(filter::Header("content-type", "text/plain")),
/// )
/// r.route(web::route()
/// .filter(
/// filter::All(filter::Get()).and(filter::Header("content-type", "text/plain")))
/// .to(|| HttpResponse::MethodNotAllowed()))
/// });
/// }
@ -85,7 +83,7 @@ impl AllFilter {
}
impl Filter for AllFilter {
fn check(&self, request: &HttpRequest) -> bool {
fn check(&self, request: &RequestHead) -> bool {
for p in &self.0 {
if !p.check(request) {
return false;
@ -104,7 +102,7 @@ pub fn Not<F: Filter + 'static>(filter: F) -> NotFilter {
pub struct NotFilter(Box<Filter>);
impl Filter for NotFilter {
fn check(&self, request: &HttpRequest) -> bool {
fn check(&self, request: &RequestHead) -> bool {
!self.0.check(request)
}
}
@ -114,8 +112,8 @@ impl Filter for NotFilter {
pub struct MethodFilter(http::Method);
impl Filter for MethodFilter {
fn check(&self, request: &HttpRequest) -> bool {
request.method() == self.0
fn check(&self, request: &RequestHead) -> bool {
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);
impl Filter for HeaderFilter {
fn check(&self, req: &HttpRequest) -> bool {
if let Some(val) = req.headers().get(&self.0) {
fn check(&self, req: &RequestHead) -> bool {
if let Some(val) = req.headers.get(&self.0) {
return val == self.1;
}
false
@ -219,7 +217,7 @@ impl Filter for HeaderFilter {
// }
// impl Filter for HostFilter {
// fn check(&self, _req: &HttpRequest) -> bool {
// fn check(&self, _req: &RequestHead) -> bool {
// // let info = req.connection_info();
// // if let Some(ref scheme) = self.1 {
// // 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::responder::Responder;
use crate::service::{ServiceRequest, ServiceResponse};
use crate::service::{ServiceFromRequest, ServiceRequest, ServiceResponse};
/// 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>;
/// 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
@ -306,7 +306,7 @@ impl<P, T: FromRequest<P>> Default for Extract<P, T> {
impl<P, T: FromRequest<P>> NewService for Extract<P, T> {
type Request = ServiceRequest<P>;
type Response = (T, HttpRequest);
type Error = (Error, ServiceRequest<P>);
type Error = (Error, ServiceFromRequest<P>);
type InitError = ();
type Service = ExtractService<P, T>;
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> {
type Request = ServiceRequest<P>;
type Response = (T, HttpRequest);
type Error = (Error, ServiceRequest<P>);
type Error = (Error, ServiceFromRequest<P>);
type Future = ExtractResponse<P, T>;
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
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 {
fut: T::from_request(&mut 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>> {
req: Option<ServiceRequest<P>>,
req: Option<ServiceFromRequest<P>>,
fut: T::Future,
}
impl<P, T: FromRequest<P>> Future for ExtractResponse<P, T> {
type Item = (T, HttpRequest);
type Error = (Error, ServiceRequest<P>);
type Error = (Error, ServiceFromRequest<P>);
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
let item = try_ready!(self

View file

@ -25,12 +25,91 @@ pub use crate::handler::FromRequest;
pub use crate::request::HttpRequest;
pub use crate::resource::Resource;
pub use crate::responder::{Either, Responder};
pub use crate::route::Route;
pub use crate::service::{ServiceRequest, ServiceResponse};
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 use crate::app::AppRouter;
pub use crate::handler::{AsyncFactory, Extract, Factory, Handle};
pub use crate::route::{Route, RouteBuilder};
// pub use crate::info::ConnectionInfo;
}

View file

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

View file

@ -1,7 +1,7 @@
use std::cell::RefCell;
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::{
ApplyNewService, IntoNewService, IntoNewTransform, NewService, NewTransform, Service,
@ -11,7 +11,7 @@ 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::route::{CreateRouteService, Route, RouteService};
use crate::service::{ServiceRequest, ServiceResponse};
type HttpService<P> = BoxedService<ServiceRequest<P>, ServiceResponse, ()>;
@ -74,92 +74,8 @@ where
/// .finish();
/// }
/// ```
pub fn route<F>(mut self, f: F) -> Self
where
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)));
pub fn route(mut self, route: Route<P>) -> Self {
self.routes.push(route);
self
}
@ -187,7 +103,7 @@ where
I: FromRequest<P> + 'static,
R: Responder + 'static,
{
self.routes.push(Route::build().to(handler));
self.routes.push(Route::new().to(handler));
self
}
@ -227,7 +143,7 @@ where
R::Item: Into<Response>,
R::Error: Into<Error>,
{
self.routes.push(Route::build().to_async(handler));
self.routes.push(Route::new().to_async(handler));
self
}

View file

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

View file

@ -1,9 +1,11 @@
use std::cell::{Ref, RefMut};
use std::rc::Rc;
use actix_http::body::{Body, MessageBody, ResponseBody};
use actix_http::http::HeaderMap;
use actix_http::http::{HeaderMap, Method, Uri, Version};
use actix_http::{
Error, Extensions, HttpMessage, Payload, Request, Response, ResponseHead,
Error, Extensions, HttpMessage, Payload, Request, RequestHead, Response,
ResponseHead,
};
use actix_router::{Path, Url};
@ -27,11 +29,6 @@ impl<P> ServiceRequest<P> {
}
}
#[inline]
pub fn request(&self) -> &HttpRequest {
&self.req
}
#[inline]
pub fn into_request(self) -> HttpRequest {
self.req
@ -49,10 +46,93 @@ impl<P> ServiceRequest<P> {
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]
pub fn match_info_mut(&mut self) -> &mut Path<Url> {
&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> {
@ -70,10 +150,65 @@ impl<P> HttpMessage 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;
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 crate::handler::FromRequest;
use crate::service::ServiceRequest;
use crate::service::ServiceFromRequest;
/// Application state factory
pub(crate) trait StateFactory {
@ -50,7 +50,7 @@ impl<S: 'static, P> FromRequest<P> for State<S> {
type Future = FutureResult<Self, Error>;
#[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>>() {
ok(st.clone())
} else {

View file

@ -12,7 +12,7 @@ use flate2::write::ZlibDecoder;
use futures::stream::once; //Future, Stream
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 \
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() {
let mut srv = TestServer::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(
App::new()
.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(
App::new()
.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(
App::new()
.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()
.middleware(middleware::Compress::new(ContentEncoding::Gzip))
.resource("/", |r| {
r.get(move || {
r.route(web::get().to(move || {
Response::Ok().streaming(once(Ok::<_, Error>(
Bytes::from_static(STR.as_ref()),
)))
})
}))
}),
)
});
@ -178,11 +182,11 @@ fn test_body_br_streaming() {
App::new()
.middleware(middleware::Compress::new(ContentEncoding::Br))
.resource("/", |r| {
r.get(move || {
r.route(web::to(move || {
Response::Ok().streaming(once(Ok::<_, Error>(
Bytes::from_static(STR.as_ref()),
)))
})
}))
}),
)
});
@ -205,7 +209,7 @@ fn test_body_br_streaming() {
fn test_head_binary() {
let mut srv = TestServer::new(move || {
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() {
let mut srv = TestServer::new(move || {
h1::H1Service::new(App::new().resource("/", |r| {
r.get(move || {
r.route(web::to(move || {
Response::Ok()
.no_chunking()
.content_length(STR.len() as u64)
.streaming(once(Ok::<_, Error>(Bytes::from_static(STR.as_ref()))))
})
}))
}))
});
@ -252,7 +256,7 @@ fn test_body_deflate() {
h1::H1Service::new(
App::new()
.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(
App::new()
.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)))),
)
});