Skip to content

Commit

Permalink
added extractor configuration system
Browse files Browse the repository at this point in the history
  • Loading branch information
fafhrd91 committed Mar 3, 2019
1 parent 08fcb68 commit 6df85e3
Show file tree
Hide file tree
Showing 9 changed files with 210 additions and 50 deletions.
83 changes: 66 additions & 17 deletions src/extractor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use actix_http::http::StatusCode;
use actix_http::{HttpMessage, Response};
use actix_router::PathDeserializer;

use crate::handler::FromRequest;
use crate::handler::{ConfigStorage, ExtractorConfig, FromRequest};
use crate::request::HttpRequest;
use crate::responder::Responder;
use crate::service::ServiceFromRequest;
Expand Down Expand Up @@ -133,6 +133,7 @@ where
{
type Error = Error;
type Future = FutureResult<Self, Error>;
type Config = ();

#[inline]
fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future {
Expand Down Expand Up @@ -219,6 +220,7 @@ where
{
type Error = Error;
type Future = FutureResult<Self, Error>;
type Config = ();

#[inline]
fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future {
Expand Down Expand Up @@ -299,16 +301,18 @@ where
{
type Error = Error;
type Future = Box<Future<Item = Self, Error = Error>>;
type Config = FormConfig;

#[inline]
fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future {
let cfg = FormConfig::default();

let req2 = req.clone();
let cfg = req.load_config::<FormConfig>();

let limit = cfg.limit;
let err = Rc::clone(&cfg.ehandler);
Box::new(
UrlEncoded::new(req)
.limit(cfg.limit)
.limit(limit)
.map_err(move |e| (*err)(e, &req2))
.map(Form),
)
Expand Down Expand Up @@ -356,20 +360,21 @@ impl<T: fmt::Display> fmt::Display for Form<T> {
/// );
/// }
/// ```
#[derive(Clone)]
pub struct FormConfig {
limit: usize,
ehandler: Rc<Fn(UrlencodedError, &HttpRequest) -> Error>,
}

impl FormConfig {
/// 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
}

/// 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
F: Fn(UrlencodedError, &HttpRequest) -> Error + 'static,
{
Expand All @@ -378,6 +383,8 @@ impl FormConfig {
}
}

impl ExtractorConfig for FormConfig {}

impl Default for FormConfig {
fn default() -> Self {
FormConfig {
Expand Down Expand Up @@ -509,16 +516,18 @@ where
{
type Error = Error;
type Future = Box<Future<Item = Self, Error = Error>>;
type Config = JsonConfig;

#[inline]
fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future {
let cfg = JsonConfig::default();

let req2 = req.clone();
let cfg = req.load_config::<JsonConfig>();

let limit = cfg.limit;
let err = Rc::clone(&cfg.ehandler);
Box::new(
JsonBody::new(req)
.limit(cfg.limit)
.limit(limit)
.map_err(move |e| (*err)(e, &req2))
.map(Json),
)
Expand Down Expand Up @@ -555,20 +564,21 @@ where
/// });
/// }
/// ```
#[derive(Clone)]
pub struct JsonConfig {
limit: usize,
ehandler: Rc<Fn(JsonPayloadError, &HttpRequest) -> Error>,
}

impl JsonConfig {
/// 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
}

/// 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
F: Fn(JsonPayloadError, &HttpRequest) -> Error + 'static,
{
Expand All @@ -577,6 +587,8 @@ impl JsonConfig {
}
}

impl ExtractorConfig for JsonConfig {}

impl Default for JsonConfig {
fn default() -> Self {
JsonConfig {
Expand Down Expand Up @@ -617,16 +629,18 @@ where
type Error = Error;
type Future =
Either<Box<Future<Item = Bytes, Error = Error>>, FutureResult<Bytes, Error>>;
type Config = PayloadConfig;

#[inline]
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) {
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()))
}
}

Expand Down Expand Up @@ -664,10 +678,11 @@ where
type Error = Error;
type Future =
Either<Box<Future<Item = String, Error = Error>>, FutureResult<String, Error>>;
type Config = PayloadConfig;

#[inline]
fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future {
let cfg = PayloadConfig::default();
let cfg = req.load_config::<PayloadConfig>();

// check content-type
if let Err(e) = cfg.check_mimetype(req) {
Expand All @@ -679,10 +694,11 @@ where
Ok(enc) => enc,
Err(e) => return Either::B(err(e.into())),
};
let limit = cfg.limit;

Either::A(Box::new(
MessageBody::new(req)
.limit(cfg.limit)
.limit(limit)
.from_err()
.and_then(move |body| {
let enc: *const Encoding = encoding as *const Encoding;
Expand Down Expand Up @@ -753,6 +769,7 @@ where
{
type Error = Error;
type Future = Box<Future<Item = Option<T>, Error = Error>>;
type Config = T::Config;

#[inline]
fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future {
Expand Down Expand Up @@ -816,6 +833,7 @@ where
{
type Error = Error;
type Future = Box<Future<Item = Result<T, T::Error>, Error = Error>>;
type Config = T::Config;

#[inline]
fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future {
Expand All @@ -827,21 +845,27 @@ where
}

/// Payload configuration for request's payload.
#[derive(Clone)]
pub struct PayloadConfig {
limit: usize,
mimetype: Option<Mime>,
}

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
pub fn limit(&mut self, limit: usize) -> &mut Self {
pub fn limit(mut self, limit: usize) -> Self {
self.limit = limit;
self
}

/// Set required mime-type of the request. By default mime type is not
/// enforced.
pub fn mimetype(&mut self, mt: Mime) -> &mut Self {
pub fn mimetype(mut self, mt: Mime) -> Self {
self.mimetype = Some(mt);
self
}
Expand All @@ -867,6 +891,8 @@ impl PayloadConfig {
}
}

impl ExtractorConfig for PayloadConfig {}

impl Default for PayloadConfig {
fn default() -> Self {
PayloadConfig {
Expand All @@ -876,13 +902,24 @@ 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)),+} => {

/// FromRequest implementation for tuple
impl<P, $($T: FromRequest<P> + 'static),+> FromRequest<P> for ($($T,)+)
{
type Error = Error;
type Future = $fut_type<P, $($T),+>;
type Config = ($($T::Config,)+);

fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future {
$fut_type {
Expand Down Expand Up @@ -932,6 +969,7 @@ macro_rules! tuple_from_req ({$fut_type:ident, $(($n:tt, $T:ident)),+} => {
impl<P> FromRequest<P> for () {
type Error = Error;
type Future = FutureResult<(), Error>;
type Config = ();

fn from_request(_req: &mut ServiceFromRequest<P>) -> Self::Future {
ok(())
Expand All @@ -942,6 +980,17 @@ impl<P> FromRequest<P> for () {
mod m {
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!(TupleFromRequest2, (0, A), (1, B));
tuple_from_req!(TupleFromRequest3, (0, A), (1, B), (2, C));
Expand Down
58 changes: 46 additions & 12 deletions src/handler.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use std::cell::RefCell;
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 futures::future::{ok, FutureResult};
use futures::{try_ready, Async, Future, IntoFuture, Poll};
Expand All @@ -19,10 +21,41 @@ pub trait FromRequest<P>: Sized {
/// Future that resolves to a Self
type Future: Future<Item = Self, Error = Self::Error>;

/// Configuration for the extractor
type Config: ExtractorConfig;

/// Convert request to a Self
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
pub trait Factory<T, R>: Clone
where
Expand Down Expand Up @@ -288,18 +321,16 @@ where

/// Extract arguments from request
pub struct Extract<P, T: FromRequest<P>> {
config: Rc<RefCell<Option<Rc<Extensions>>>>,
_t: PhantomData<(P, T)>,
}

impl<P, T: FromRequest<P>> Extract<P, T> {
pub fn new() -> Self {
Extract { _t: PhantomData }
}
}

impl<P, T: FromRequest<P>> Default for Extract<P, T> {
fn default() -> Self {
Self::new()
pub fn new(config: Rc<RefCell<Option<Rc<Extensions>>>>) -> Self {
Extract {
config,
_t: PhantomData,
}
}
}

Expand All @@ -312,11 +343,15 @@ impl<P, T: FromRequest<P>> NewService for Extract<P, T> {
type Future = FutureResult<Self::Service, ()>;

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>> {
config: Option<Rc<Extensions>>,
_t: PhantomData<(P, T)>,
}

Expand All @@ -331,7 +366,7 @@ impl<P, T: FromRequest<P>> Service for ExtractService<P, T> {
}

fn call(&mut self, req: ServiceRequest<P>) -> Self::Future {
let mut req = req.into();
let mut req = ServiceFromRequest::new(req, self.config.clone());
ExtractResponse {
fut: T::from_request(&mut req),
req: Some(req),
Expand Down Expand Up @@ -365,7 +400,6 @@ impl<P, T: FromRequest<P>> Future for ExtractResponse<P, T> {
macro_rules! factory_tuple ({ $(($n:tt, $T:ident)),+} => {
impl<Func, $($T,)+ Res> Factory<($($T,)+), Res> for Func
where Func: Fn($($T,)+) -> Res + Clone + 'static,
//$($T,)+
Res: Responder + 'static,
{
fn call(&self, param: ($($T,)+)) -> Res {
Expand Down
Loading

0 comments on commit 6df85e3

Please sign in to comment.