1
0
mirror of https://github.com/actix/actix-extras.git synced 2024-11-28 09:42:40 +01:00

added extractor configuration system

This commit is contained in:
Nikolay Kim 2019-03-03 00:57:48 -08:00
parent 08fcb6891e
commit 6df85e32df
9 changed files with 210 additions and 50 deletions

View File

@ -23,7 +23,7 @@ use actix_http::http::StatusCode;
use actix_http::{HttpMessage, Response}; use actix_http::{HttpMessage, Response};
use actix_router::PathDeserializer; use actix_router::PathDeserializer;
use crate::handler::FromRequest; use crate::handler::{ConfigStorage, ExtractorConfig, FromRequest};
use crate::request::HttpRequest; use crate::request::HttpRequest;
use crate::responder::Responder; use crate::responder::Responder;
use crate::service::ServiceFromRequest; use crate::service::ServiceFromRequest;
@ -133,6 +133,7 @@ where
{ {
type Error = Error; type Error = Error;
type Future = FutureResult<Self, Error>; type Future = FutureResult<Self, Error>;
type Config = ();
#[inline] #[inline]
fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future { fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future {
@ -219,6 +220,7 @@ where
{ {
type Error = Error; type Error = Error;
type Future = FutureResult<Self, Error>; type Future = FutureResult<Self, Error>;
type Config = ();
#[inline] #[inline]
fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future { fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future {
@ -299,16 +301,18 @@ where
{ {
type Error = Error; type Error = Error;
type Future = Box<Future<Item = Self, Error = Error>>; type Future = Box<Future<Item = Self, Error = Error>>;
type Config = FormConfig;
#[inline] #[inline]
fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future { fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future {
let cfg = FormConfig::default();
let req2 = req.clone(); let req2 = req.clone();
let cfg = req.load_config::<FormConfig>();
let limit = cfg.limit;
let err = Rc::clone(&cfg.ehandler); let err = Rc::clone(&cfg.ehandler);
Box::new( Box::new(
UrlEncoded::new(req) UrlEncoded::new(req)
.limit(cfg.limit) .limit(limit)
.map_err(move |e| (*err)(e, &req2)) .map_err(move |e| (*err)(e, &req2))
.map(Form), .map(Form),
) )
@ -356,6 +360,7 @@ impl<T: fmt::Display> fmt::Display for Form<T> {
/// ); /// );
/// } /// }
/// ``` /// ```
#[derive(Clone)]
pub struct FormConfig { pub struct FormConfig {
limit: usize, limit: usize,
ehandler: Rc<Fn(UrlencodedError, &HttpRequest) -> Error>, ehandler: Rc<Fn(UrlencodedError, &HttpRequest) -> Error>,
@ -363,13 +368,13 @@ pub struct FormConfig {
impl FormConfig { impl FormConfig {
/// Change max size of payload. By default max size is 256Kb /// Change max size of payload. By default max size is 256Kb
pub fn limit(&mut self, limit: usize) -> &mut Self { pub fn limit(mut self, limit: usize) -> Self {
self.limit = limit; self.limit = limit;
self self
} }
/// Set custom error handler /// Set custom error handler
pub fn error_handler<F>(&mut self, f: F) -> &mut Self pub fn error_handler<F>(mut self, f: F) -> Self
where where
F: Fn(UrlencodedError, &HttpRequest) -> Error + 'static, F: Fn(UrlencodedError, &HttpRequest) -> Error + 'static,
{ {
@ -378,6 +383,8 @@ impl FormConfig {
} }
} }
impl ExtractorConfig for FormConfig {}
impl Default for FormConfig { impl Default for FormConfig {
fn default() -> Self { fn default() -> Self {
FormConfig { FormConfig {
@ -509,16 +516,18 @@ where
{ {
type Error = Error; type Error = Error;
type Future = Box<Future<Item = Self, Error = Error>>; type Future = Box<Future<Item = Self, Error = Error>>;
type Config = JsonConfig;
#[inline] #[inline]
fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future { fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future {
let cfg = JsonConfig::default();
let req2 = req.clone(); let req2 = req.clone();
let cfg = req.load_config::<JsonConfig>();
let limit = cfg.limit;
let err = Rc::clone(&cfg.ehandler); let err = Rc::clone(&cfg.ehandler);
Box::new( Box::new(
JsonBody::new(req) JsonBody::new(req)
.limit(cfg.limit) .limit(limit)
.map_err(move |e| (*err)(e, &req2)) .map_err(move |e| (*err)(e, &req2))
.map(Json), .map(Json),
) )
@ -555,6 +564,7 @@ where
/// }); /// });
/// } /// }
/// ``` /// ```
#[derive(Clone)]
pub struct JsonConfig { pub struct JsonConfig {
limit: usize, limit: usize,
ehandler: Rc<Fn(JsonPayloadError, &HttpRequest) -> Error>, ehandler: Rc<Fn(JsonPayloadError, &HttpRequest) -> Error>,
@ -562,13 +572,13 @@ pub struct JsonConfig {
impl JsonConfig { impl JsonConfig {
/// Change max size of payload. By default max size is 256Kb /// Change max size of payload. By default max size is 256Kb
pub fn limit(&mut self, limit: usize) -> &mut Self { pub fn limit(mut self, limit: usize) -> Self {
self.limit = limit; self.limit = limit;
self self
} }
/// Set custom error handler /// Set custom error handler
pub fn error_handler<F>(&mut self, f: F) -> &mut Self pub fn error_handler<F>(mut self, f: F) -> Self
where where
F: Fn(JsonPayloadError, &HttpRequest) -> Error + 'static, F: Fn(JsonPayloadError, &HttpRequest) -> Error + 'static,
{ {
@ -577,6 +587,8 @@ impl JsonConfig {
} }
} }
impl ExtractorConfig for JsonConfig {}
impl Default for JsonConfig { impl Default for JsonConfig {
fn default() -> Self { fn default() -> Self {
JsonConfig { JsonConfig {
@ -617,16 +629,18 @@ where
type Error = Error; type Error = Error;
type Future = type Future =
Either<Box<Future<Item = Bytes, Error = Error>>, FutureResult<Bytes, Error>>; Either<Box<Future<Item = Bytes, Error = Error>>, FutureResult<Bytes, Error>>;
type Config = PayloadConfig;
#[inline] #[inline]
fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future { fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future {
let cfg = PayloadConfig::default(); let cfg = req.load_config::<PayloadConfig>();
if let Err(e) = cfg.check_mimetype(req) { if let Err(e) = cfg.check_mimetype(req) {
return Either::B(err(e)); return Either::B(err(e));
} }
Either::A(Box::new(MessageBody::new(req).limit(cfg.limit).from_err())) let limit = cfg.limit;
Either::A(Box::new(MessageBody::new(req).limit(limit).from_err()))
} }
} }
@ -664,10 +678,11 @@ where
type Error = Error; type Error = Error;
type Future = type Future =
Either<Box<Future<Item = String, Error = Error>>, FutureResult<String, Error>>; Either<Box<Future<Item = String, Error = Error>>, FutureResult<String, Error>>;
type Config = PayloadConfig;
#[inline] #[inline]
fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future { fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future {
let cfg = PayloadConfig::default(); let cfg = req.load_config::<PayloadConfig>();
// check content-type // check content-type
if let Err(e) = cfg.check_mimetype(req) { if let Err(e) = cfg.check_mimetype(req) {
@ -679,10 +694,11 @@ where
Ok(enc) => enc, Ok(enc) => enc,
Err(e) => return Either::B(err(e.into())), Err(e) => return Either::B(err(e.into())),
}; };
let limit = cfg.limit;
Either::A(Box::new( Either::A(Box::new(
MessageBody::new(req) MessageBody::new(req)
.limit(cfg.limit) .limit(limit)
.from_err() .from_err()
.and_then(move |body| { .and_then(move |body| {
let enc: *const Encoding = encoding as *const Encoding; let enc: *const Encoding = encoding as *const Encoding;
@ -753,6 +769,7 @@ where
{ {
type Error = Error; type Error = Error;
type Future = Box<Future<Item = Option<T>, Error = Error>>; type Future = Box<Future<Item = Option<T>, Error = Error>>;
type Config = T::Config;
#[inline] #[inline]
fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future { fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future {
@ -816,6 +833,7 @@ where
{ {
type Error = Error; type Error = Error;
type Future = Box<Future<Item = Result<T, T::Error>, Error = Error>>; type Future = Box<Future<Item = Result<T, T::Error>, Error = Error>>;
type Config = T::Config;
#[inline] #[inline]
fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future { fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future {
@ -827,21 +845,27 @@ where
} }
/// Payload configuration for request's payload. /// Payload configuration for request's payload.
#[derive(Clone)]
pub struct PayloadConfig { pub struct PayloadConfig {
limit: usize, limit: usize,
mimetype: Option<Mime>, mimetype: Option<Mime>,
} }
impl PayloadConfig { impl PayloadConfig {
/// Create `PayloadConfig` instance and set max size of payload.
pub fn new(limit: usize) -> Self {
Self::default().limit(limit)
}
/// Change max size of payload. By default max size is 256Kb /// Change max size of payload. By default max size is 256Kb
pub fn limit(&mut self, limit: usize) -> &mut Self { pub fn limit(mut self, limit: usize) -> Self {
self.limit = limit; self.limit = limit;
self self
} }
/// Set required mime-type of the request. By default mime type is not /// Set required mime-type of the request. By default mime type is not
/// enforced. /// enforced.
pub fn mimetype(&mut self, mt: Mime) -> &mut Self { pub fn mimetype(mut self, mt: Mime) -> Self {
self.mimetype = Some(mt); self.mimetype = Some(mt);
self self
} }
@ -867,6 +891,8 @@ impl PayloadConfig {
} }
} }
impl ExtractorConfig for PayloadConfig {}
impl Default for PayloadConfig { impl Default for PayloadConfig {
fn default() -> Self { fn default() -> Self {
PayloadConfig { PayloadConfig {
@ -876,6 +902,16 @@ impl Default for PayloadConfig {
} }
} }
macro_rules! tuple_config ({ $($T:ident),+} => {
impl<$($T,)+> ExtractorConfig for ($($T,)+)
where $($T: ExtractorConfig + Clone,)+
{
fn store_default(ext: &mut ConfigStorage) {
$($T::store_default(ext);)+
}
}
});
macro_rules! tuple_from_req ({$fut_type:ident, $(($n:tt, $T:ident)),+} => { macro_rules! tuple_from_req ({$fut_type:ident, $(($n:tt, $T:ident)),+} => {
/// FromRequest implementation for tuple /// FromRequest implementation for tuple
@ -883,6 +919,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),+>;
type Config = ($($T::Config,)+);
fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future { fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future {
$fut_type { $fut_type {
@ -932,6 +969,7 @@ macro_rules! tuple_from_req ({$fut_type:ident, $(($n:tt, $T:ident)),+} => {
impl<P> FromRequest<P> for () { impl<P> FromRequest<P> for () {
type Error = Error; type Error = Error;
type Future = FutureResult<(), Error>; type Future = FutureResult<(), Error>;
type Config = ();
fn from_request(_req: &mut ServiceFromRequest<P>) -> Self::Future { fn from_request(_req: &mut ServiceFromRequest<P>) -> Self::Future {
ok(()) ok(())
@ -942,6 +980,17 @@ impl<P> FromRequest<P> for () {
mod m { mod m {
use super::*; use super::*;
tuple_config!(A);
tuple_config!(A, B);
tuple_config!(A, B, C);
tuple_config!(A, B, C, D);
tuple_config!(A, B, C, D, E);
tuple_config!(A, B, C, D, E, F);
tuple_config!(A, B, C, D, E, F, G);
tuple_config!(A, B, C, D, E, F, G, H);
tuple_config!(A, B, C, D, E, F, G, H, I);
tuple_config!(A, B, C, D, E, F, G, H, I, J);
tuple_from_req!(TupleFromRequest1, (0, A)); tuple_from_req!(TupleFromRequest1, (0, A));
tuple_from_req!(TupleFromRequest2, (0, A), (1, B)); tuple_from_req!(TupleFromRequest2, (0, A), (1, B));
tuple_from_req!(TupleFromRequest3, (0, A), (1, B), (2, C)); tuple_from_req!(TupleFromRequest3, (0, A), (1, B), (2, C));

View File

@ -1,6 +1,8 @@
use std::cell::RefCell;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::rc::Rc;
use actix_http::{Error, Response}; use actix_http::{Error, Extensions, Response};
use actix_service::{NewService, Service, Void}; use actix_service::{NewService, Service, Void};
use futures::future::{ok, FutureResult}; use futures::future::{ok, FutureResult};
use futures::{try_ready, Async, Future, IntoFuture, Poll}; use futures::{try_ready, Async, Future, IntoFuture, Poll};
@ -19,10 +21,41 @@ pub trait FromRequest<P>: Sized {
/// Future that resolves to a Self /// Future that resolves to a Self
type Future: Future<Item = Self, Error = Self::Error>; type Future: Future<Item = Self, Error = Self::Error>;
/// Configuration for the extractor
type Config: ExtractorConfig;
/// Convert request to a Self /// Convert request to a Self
fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future; fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future;
} }
/// Storage for extractor configs
#[derive(Default)]
pub struct ConfigStorage {
pub(crate) storage: Option<Rc<Extensions>>,
}
impl ConfigStorage {
pub fn store<C: ExtractorConfig>(&mut self, config: C) {
if self.storage.is_none() {
self.storage = Some(Rc::new(Extensions::new()));
}
if let Some(ref mut ext) = self.storage {
Rc::get_mut(ext).unwrap().insert(config);
}
}
}
pub trait ExtractorConfig: Default + Clone + 'static {
/// Set default configuration to config storage
fn store_default(ext: &mut ConfigStorage) {
ext.store(Self::default())
}
}
impl ExtractorConfig for () {
fn store_default(_: &mut ConfigStorage) {}
}
/// Handler converter factory /// Handler converter factory
pub trait Factory<T, R>: Clone pub trait Factory<T, R>: Clone
where where
@ -288,18 +321,16 @@ where
/// Extract arguments from request /// Extract arguments from request
pub struct Extract<P, T: FromRequest<P>> { pub struct Extract<P, T: FromRequest<P>> {
config: Rc<RefCell<Option<Rc<Extensions>>>>,
_t: PhantomData<(P, T)>, _t: PhantomData<(P, T)>,
} }
impl<P, T: FromRequest<P>> Extract<P, T> { impl<P, T: FromRequest<P>> Extract<P, T> {
pub fn new() -> Self { pub fn new(config: Rc<RefCell<Option<Rc<Extensions>>>>) -> Self {
Extract { _t: PhantomData } Extract {
config,
_t: PhantomData,
} }
}
impl<P, T: FromRequest<P>> Default for Extract<P, T> {
fn default() -> Self {
Self::new()
} }
} }
@ -312,11 +343,15 @@ impl<P, T: FromRequest<P>> NewService for Extract<P, T> {
type Future = FutureResult<Self::Service, ()>; type Future = FutureResult<Self::Service, ()>;
fn new_service(&self, _: &()) -> Self::Future { fn new_service(&self, _: &()) -> Self::Future {
ok(ExtractService { _t: PhantomData }) ok(ExtractService {
_t: PhantomData,
config: self.config.borrow().clone(),
})
} }
} }
pub struct ExtractService<P, T: FromRequest<P>> { pub struct ExtractService<P, T: FromRequest<P>> {
config: Option<Rc<Extensions>>,
_t: PhantomData<(P, T)>, _t: PhantomData<(P, T)>,
} }
@ -331,7 +366,7 @@ impl<P, T: FromRequest<P>> Service for ExtractService<P, T> {
} }
fn call(&mut self, req: ServiceRequest<P>) -> Self::Future { fn call(&mut self, req: ServiceRequest<P>) -> Self::Future {
let mut req = req.into(); let mut req = ServiceFromRequest::new(req, self.config.clone());
ExtractResponse { ExtractResponse {
fut: T::from_request(&mut req), fut: T::from_request(&mut req),
req: Some(req), req: Some(req),
@ -365,7 +400,6 @@ impl<P, T: FromRequest<P>> Future for ExtractResponse<P, T> {
macro_rules! factory_tuple ({ $(($n:tt, $T:ident)),+} => { macro_rules! factory_tuple ({ $(($n:tt, $T:ident)),+} => {
impl<Func, $($T,)+ Res> Factory<($($T,)+), Res> for Func impl<Func, $($T,)+ Res> Factory<($($T,)+), Res> for Func
where Func: Fn($($T,)+) -> Res + Clone + 'static, where Func: Fn($($T,)+) -> Res + Clone + 'static,
//$($T,)+
Res: Responder + 'static, Res: Responder + 'static,
{ {
fn call(&self, param: ($($T,)+)) -> Res { fn call(&self, param: ($($T,)+)) -> Res {

View File

@ -1,7 +1,7 @@
#![allow(clippy::type_complexity)] #![allow(clippy::type_complexity)]
mod app; mod app;
mod extractor; pub mod extractor;
pub mod handler; pub mod handler;
// mod info; // mod info;
pub mod blocking; pub mod blocking;
@ -20,7 +20,7 @@ pub use actix_http::Response as HttpResponse;
pub use actix_http::{http, Error, HttpMessage, ResponseError}; pub use actix_http::{http, Error, HttpMessage, ResponseError};
pub use crate::app::App; pub use crate::app::App;
pub use crate::extractor::{Form, Json, Path, Query}; pub use crate::extractor::{Form, Json, Path, PayloadConfig, Query};
pub use crate::handler::FromRequest; 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;

View File

@ -143,6 +143,7 @@ impl HttpMessage for HttpRequest {
impl<P> FromRequest<P> for HttpRequest { impl<P> FromRequest<P> for HttpRequest {
type Error = Error; type Error = Error;
type Future = FutureResult<Self, Error>; type Future = FutureResult<Self, Error>;
type Config = ();
#[inline] #[inline]
fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future { fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future {

View File

@ -75,7 +75,7 @@ where
/// } /// }
/// ``` /// ```
pub fn route(mut self, route: Route<P>) -> Self { pub fn route(mut self, route: Route<P>) -> Self {
self.routes.push(route); self.routes.push(route.finish());
self self
} }

View File

@ -1,11 +1,15 @@
use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
use actix_http::{http::Method, Error, Response}; use actix_http::{http::Method, Error, Extensions, Response};
use actix_service::{NewService, Service}; use actix_service::{NewService, Service};
use futures::{Async, Future, IntoFuture, Poll}; 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, ConfigStorage, Extract, ExtractorConfig, Factory,
FromRequest, Handle,
};
use crate::responder::Responder; use crate::responder::Responder;
use crate::service::{ServiceFromRequest, ServiceRequest, ServiceResponse}; use crate::service::{ServiceFromRequest, ServiceRequest, ServiceResponse};
use crate::HttpResponse; use crate::HttpResponse;
@ -37,33 +41,50 @@ type BoxedRouteNewService<Req, Res> = Box<
pub struct Route<P> { pub struct Route<P> {
service: BoxedRouteNewService<ServiceRequest<P>, ServiceResponse>, service: BoxedRouteNewService<ServiceRequest<P>, ServiceResponse>,
filters: Rc<Vec<Box<Filter>>>, filters: Rc<Vec<Box<Filter>>>,
config: ConfigStorage,
config_ref: Rc<RefCell<Option<Rc<Extensions>>>>,
} }
impl<P: 'static> Route<P> { impl<P: 'static> Route<P> {
/// Create new route which matches any request.
pub fn new() -> Route<P> { pub fn new() -> Route<P> {
let config_ref = Rc::new(RefCell::new(None));
Route { Route {
service: Box::new(RouteNewService::new(Extract::new().and_then( service: Box::new(RouteNewService::new(
Extract::new(config_ref.clone()).and_then(
Handle::new(|| HttpResponse::NotFound()).map_err(|_| panic!()), Handle::new(|| HttpResponse::NotFound()).map_err(|_| panic!()),
))), ),
)),
filters: Rc::new(Vec::new()), filters: Rc::new(Vec::new()),
config: ConfigStorage::default(),
config_ref,
} }
} }
/// Create new `GET` route.
pub fn get() -> Route<P> { pub fn get() -> Route<P> {
Route::new().method(Method::GET) Route::new().method(Method::GET)
} }
/// Create new `POST` route.
pub fn post() -> Route<P> { pub fn post() -> Route<P> {
Route::new().method(Method::POST) Route::new().method(Method::POST)
} }
/// Create new `PUT` route.
pub fn put() -> Route<P> { pub fn put() -> Route<P> {
Route::new().method(Method::PUT) Route::new().method(Method::PUT)
} }
/// Create new `DELETE` route.
pub fn delete() -> Route<P> { pub fn delete() -> Route<P> {
Route::new().method(Method::DELETE) Route::new().method(Method::DELETE)
} }
pub(crate) fn finish(self) -> Self {
*self.config_ref.borrow_mut() = self.config.storage.clone();
self
}
} }
impl<P> NewService for Route<P> { impl<P> NewService for Route<P> {
@ -260,8 +281,10 @@ impl<P: 'static> Route<P> {
T: FromRequest<P> + 'static, T: FromRequest<P> + 'static,
R: Responder + 'static, R: Responder + 'static,
{ {
T::Config::store_default(&mut self.config);
self.service = Box::new(RouteNewService::new( self.service = Box::new(RouteNewService::new(
Extract::new().and_then(Handle::new(handler).map_err(|_| panic!())), Extract::new(self.config_ref.clone())
.and_then(Handle::new(handler).map_err(|_| panic!())),
)); ));
self self
} }
@ -305,10 +328,39 @@ impl<P: 'static> Route<P> {
R::Error: Into<Error>, R::Error: Into<Error>,
{ {
self.service = Box::new(RouteNewService::new( self.service = Box::new(RouteNewService::new(
Extract::new().and_then(AsyncHandle::new(handler).map_err(|_| panic!())), Extract::new(self.config_ref.clone())
.and_then(AsyncHandle::new(handler).map_err(|_| panic!())),
)); ));
self self
} }
/// This method allows to add extractor configuration
/// for specific route.
///
/// ```rust
/// use actix_web::{web, extractor, App};
///
/// /// extract text data from request
/// fn index(body: String) -> String {
/// format!("Body {}!", body)
/// }
///
/// fn main() {
/// let app = App::new().resource("/index.html", |r| {
/// r.route(
/// web::get()
/// // limit size of the payload
/// .config(extractor::PayloadConfig::new(4096))
/// // register handler
/// .to(index)
/// )
/// });
/// }
/// ```
pub fn config<C: ExtractorConfig>(mut self, config: C) -> Self {
self.config.store(config);
self
}
} }
// pub struct RouteServiceBuilder<P, T, U1, U2> { // pub struct RouteServiceBuilder<P, T, U1, U2> {

View File

@ -1,3 +1,4 @@
use std::borrow::Cow;
use std::cell::{Ref, RefMut}; use std::cell::{Ref, RefMut};
use std::rc::Rc; use std::rc::Rc;
@ -167,9 +168,18 @@ impl<P> std::ops::DerefMut for ServiceRequest<P> {
pub struct ServiceFromRequest<P> { pub struct ServiceFromRequest<P> {
req: HttpRequest, req: HttpRequest,
payload: Payload<P>, payload: Payload<P>,
config: Option<Rc<Extensions>>,
} }
impl<P> ServiceFromRequest<P> { impl<P> ServiceFromRequest<P> {
pub(crate) fn new(req: ServiceRequest<P>, config: Option<Rc<Extensions>>) -> Self {
Self {
req: req.req,
payload: req.payload,
config,
}
}
#[inline] #[inline]
pub fn into_request(self) -> HttpRequest { pub fn into_request(self) -> HttpRequest {
self.req self.req
@ -180,6 +190,16 @@ impl<P> ServiceFromRequest<P> {
pub fn error_response<E: Into<Error>>(self, err: E) -> ServiceResponse { pub fn error_response<E: Into<Error>>(self, err: E) -> ServiceResponse {
ServiceResponse::new(self.req, err.into().into()) ServiceResponse::new(self.req, err.into().into())
} }
/// Load extractor configuration
pub fn load_config<T: Clone + Default + 'static>(&self) -> Cow<T> {
if let Some(ref ext) = self.config {
if let Some(cfg) = ext.get::<T>() {
return Cow::Borrowed(cfg);
}
}
Cow::Owned(T::default())
}
} }
impl<P> std::ops::Deref for ServiceFromRequest<P> { impl<P> std::ops::Deref for ServiceFromRequest<P> {
@ -204,15 +224,6 @@ impl<P> HttpMessage for ServiceFromRequest<P> {
} }
} }
impl<P> From<ServiceRequest<P>> for ServiceFromRequest<P> {
fn from(req: ServiceRequest<P>) -> Self {
Self {
req: req.req,
payload: req.payload,
}
}
}
pub struct ServiceResponse<B = Body> { pub struct ServiceResponse<B = Body> {
request: HttpRequest, request: HttpRequest,
response: Response<B>, response: Response<B>,

View File

@ -48,6 +48,7 @@ impl<S> Clone for State<S> {
impl<S: 'static, P> FromRequest<P> for State<S> { impl<S: 'static, P> FromRequest<P> for State<S> {
type Error = Error; type Error = Error;
type Future = FutureResult<Self, Error>; type Future = FutureResult<Self, Error>;
type Config = ();
#[inline] #[inline]
fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future { fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future {

View File

@ -9,7 +9,7 @@ use actix_router::{Path, Url};
use bytes::Bytes; use bytes::Bytes;
use crate::request::HttpRequest; use crate::request::HttpRequest;
use crate::service::ServiceRequest; use crate::service::{ServiceFromRequest, ServiceRequest};
/// Test `Request` builder /// Test `Request` builder
/// ///
@ -133,7 +133,7 @@ impl TestRequest {
} }
/// Complete request creation and generate `HttpRequest` instance /// Complete request creation and generate `HttpRequest` instance
pub fn request(mut self) -> HttpRequest { pub fn to_request(mut self) -> HttpRequest {
let req = self.req.finish(); let req = self.req.finish();
ServiceRequest::new( ServiceRequest::new(
@ -143,4 +143,16 @@ impl TestRequest {
) )
.into_request() .into_request()
} }
/// Complete request creation and generate `ServiceFromRequest` instance
pub fn to_from(mut self) -> ServiceFromRequest<PayloadStream> {
let req = self.req.finish();
let req = ServiceRequest::new(
Path::new(Url::new(req.uri().clone())),
req,
Rc::new(self.extensions),
);
ServiceFromRequest::new(req, None)
}
} }