mirror of
https://github.com/actix/actix-extras.git
synced 2024-11-28 01:32:57 +01:00
added extractor configuration system
This commit is contained in:
parent
08fcb6891e
commit
6df85e32df
@ -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));
|
||||||
|
@ -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 {
|
||||||
|
@ -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;
|
||||||
|
@ -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 {
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
66
src/route.rs
66
src/route.rs
@ -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(
|
||||||
Handle::new(|| HttpResponse::NotFound()).map_err(|_| panic!()),
|
Extract::new(config_ref.clone()).and_then(
|
||||||
))),
|
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> {
|
||||||
|
@ -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>,
|
||||||
|
@ -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 {
|
||||||
|
16
src/test.rs
16
src/test.rs
@ -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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user