mirror of
https://github.com/actix/actix-extras.git
synced 2024-11-28 09:42:40 +01:00
added extractor configuration
This commit is contained in:
parent
a255a6fb69
commit
df21892b5b
@ -255,8 +255,8 @@ impl<S> App<S> where S: 'static {
|
|||||||
/// });
|
/// });
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn resource<F>(mut self, path: &str, f: F) -> App<S>
|
pub fn resource<F, R>(mut self, path: &str, f: F) -> App<S>
|
||||||
where F: FnOnce(&mut ResourceHandler<S>) + 'static
|
where F: FnOnce(&mut ResourceHandler<S>) -> R + 'static
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
let parts = self.parts.as_mut().expect("Use after finish");
|
let parts = self.parts.as_mut().expect("Use after finish");
|
||||||
@ -272,8 +272,8 @@ impl<S> App<S> where S: 'static {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Default resource is used if no matched route could be found.
|
/// Default resource is used if no matched route could be found.
|
||||||
pub fn default_resource<F>(mut self, f: F) -> App<S>
|
pub fn default_resource<F, R>(mut self, f: F) -> App<S>
|
||||||
where F: FnOnce(&mut ResourceHandler<S>) + 'static
|
where F: FnOnce(&mut ResourceHandler<S>) -> R + 'static
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
let parts = self.parts.as_mut().expect("Use after finish");
|
let parts = self.parts.as_mut().expect("Use after finish");
|
||||||
|
@ -100,10 +100,11 @@ impl<T> Path<T> {
|
|||||||
impl<T, S> FromRequest<S> for Path<T>
|
impl<T, S> FromRequest<S> for Path<T>
|
||||||
where T: DeserializeOwned, S: 'static
|
where T: DeserializeOwned, S: 'static
|
||||||
{
|
{
|
||||||
|
type Config = ();
|
||||||
type Result = FutureResult<Self, Error>;
|
type Result = FutureResult<Self, Error>;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from_request(req: &HttpRequest<S>) -> Self::Result {
|
fn from_request(req: &HttpRequest<S>, _: &Self::Config) -> Self::Result {
|
||||||
let req = req.clone();
|
let req = req.clone();
|
||||||
result(de::Deserialize::deserialize(PathDeserializer::new(&req))
|
result(de::Deserialize::deserialize(PathDeserializer::new(&req))
|
||||||
.map_err(|e| e.into())
|
.map_err(|e| e.into())
|
||||||
@ -165,10 +166,11 @@ impl<T> Query<T> {
|
|||||||
impl<T, S> FromRequest<S> for Query<T>
|
impl<T, S> FromRequest<S> for Query<T>
|
||||||
where T: de::DeserializeOwned, S: 'static
|
where T: de::DeserializeOwned, S: 'static
|
||||||
{
|
{
|
||||||
|
type Config = ();
|
||||||
type Result = FutureResult<Self, Error>;
|
type Result = FutureResult<Self, Error>;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from_request(req: &HttpRequest<S>) -> Self::Result {
|
fn from_request(req: &HttpRequest<S>, _: &Self::Config) -> Self::Result {
|
||||||
let req = req.clone();
|
let req = req.clone();
|
||||||
result(serde_urlencoded::from_str::<T>(req.query_string())
|
result(serde_urlencoded::from_str::<T>(req.query_string())
|
||||||
.map_err(|e| e.into())
|
.map_err(|e| e.into())
|
||||||
@ -223,11 +225,60 @@ impl<T> DerefMut for Form<T> {
|
|||||||
impl<T, S> FromRequest<S> for Form<T>
|
impl<T, S> FromRequest<S> for Form<T>
|
||||||
where T: DeserializeOwned + 'static, S: 'static
|
where T: DeserializeOwned + 'static, S: 'static
|
||||||
{
|
{
|
||||||
|
type Config = FormConfig;
|
||||||
type Result = Box<Future<Item=Self, Error=Error>>;
|
type Result = Box<Future<Item=Self, Error=Error>>;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from_request(req: &HttpRequest<S>) -> Self::Result {
|
fn from_request(req: &HttpRequest<S>, cfg: &Self::Config) -> Self::Result {
|
||||||
Box::new(UrlEncoded::new(req.clone()).from_err().map(Form))
|
Box::new(UrlEncoded::new(req.clone())
|
||||||
|
.limit(cfg.limit)
|
||||||
|
.from_err()
|
||||||
|
.map(Form))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Form extractor configuration
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # extern crate actix_web;
|
||||||
|
/// #[macro_use] extern crate serde_derive;
|
||||||
|
/// use actix_web::{App, Form, Result, http};
|
||||||
|
///
|
||||||
|
/// #[derive(Deserialize)]
|
||||||
|
/// struct FormData {
|
||||||
|
/// username: String,
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// /// extract form data using serde, max payload size is 4k
|
||||||
|
/// fn index(form: Form<FormData>) -> Result<String> {
|
||||||
|
/// Ok(format!("Welcome {}!", form.username))
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// fn main() {
|
||||||
|
/// let app = App::new().resource(
|
||||||
|
/// "/index.html", |r| {
|
||||||
|
/// r.method(http::Method::GET)
|
||||||
|
/// .with(index)
|
||||||
|
/// .limit(4096);} // <- change form extractor configuration
|
||||||
|
/// );
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
pub struct FormConfig {
|
||||||
|
limit: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FormConfig {
|
||||||
|
|
||||||
|
/// Change max size of payload. By default max size is 256Kb
|
||||||
|
pub fn limit(&mut self, limit: usize) -> &mut Self {
|
||||||
|
self.limit = limit;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for FormConfig {
|
||||||
|
fn default() -> Self {
|
||||||
|
FormConfig{limit: 262_144}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -250,10 +301,11 @@ impl<T, S> FromRequest<S> for Form<T>
|
|||||||
/// ```
|
/// ```
|
||||||
impl<S: 'static> FromRequest<S> for Bytes
|
impl<S: 'static> FromRequest<S> for Bytes
|
||||||
{
|
{
|
||||||
|
type Config = ();
|
||||||
type Result = Box<Future<Item=Self, Error=Error>>;
|
type Result = Box<Future<Item=Self, Error=Error>>;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from_request(req: &HttpRequest<S>) -> Self::Result {
|
fn from_request(req: &HttpRequest<S>, _: &Self::Config) -> Self::Result {
|
||||||
Box::new(MessageBody::new(req.clone()).from_err())
|
Box::new(MessageBody::new(req.clone()).from_err())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -276,11 +328,12 @@ impl<S: 'static> FromRequest<S> for Bytes
|
|||||||
/// ```
|
/// ```
|
||||||
impl<S: 'static> FromRequest<S> for String
|
impl<S: 'static> FromRequest<S> for String
|
||||||
{
|
{
|
||||||
|
type Config = ();
|
||||||
type Result = Either<FutureResult<String, Error>,
|
type Result = Either<FutureResult<String, Error>,
|
||||||
Box<Future<Item=String, Error=Error>>>;
|
Box<Future<Item=String, Error=Error>>>;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from_request(req: &HttpRequest<S>) -> Self::Result {
|
fn from_request(req: &HttpRequest<S>, _: &Self::Config) -> Self::Result {
|
||||||
let encoding = match req.encoding() {
|
let encoding = match req.encoding() {
|
||||||
Err(_) => return Either::A(
|
Err(_) => return Either::A(
|
||||||
result(Err(ErrorBadRequest("Unknown request charset")))),
|
result(Err(ErrorBadRequest("Unknown request charset")))),
|
||||||
@ -325,7 +378,7 @@ mod tests {
|
|||||||
let mut req = TestRequest::with_header(header::CONTENT_LENGTH, "11").finish();
|
let mut req = TestRequest::with_header(header::CONTENT_LENGTH, "11").finish();
|
||||||
req.payload_mut().unread_data(Bytes::from_static(b"hello=world"));
|
req.payload_mut().unread_data(Bytes::from_static(b"hello=world"));
|
||||||
|
|
||||||
match Bytes::from_request(&req).poll().unwrap() {
|
match Bytes::from_request(&req, &()).poll().unwrap() {
|
||||||
Async::Ready(s) => {
|
Async::Ready(s) => {
|
||||||
assert_eq!(s, Bytes::from_static(b"hello=world"));
|
assert_eq!(s, Bytes::from_static(b"hello=world"));
|
||||||
},
|
},
|
||||||
@ -338,7 +391,7 @@ mod tests {
|
|||||||
let mut req = TestRequest::with_header(header::CONTENT_LENGTH, "11").finish();
|
let mut req = TestRequest::with_header(header::CONTENT_LENGTH, "11").finish();
|
||||||
req.payload_mut().unread_data(Bytes::from_static(b"hello=world"));
|
req.payload_mut().unread_data(Bytes::from_static(b"hello=world"));
|
||||||
|
|
||||||
match String::from_request(&req).poll().unwrap() {
|
match String::from_request(&req, &()).poll().unwrap() {
|
||||||
Async::Ready(s) => {
|
Async::Ready(s) => {
|
||||||
assert_eq!(s, "hello=world");
|
assert_eq!(s, "hello=world");
|
||||||
},
|
},
|
||||||
@ -354,7 +407,9 @@ mod tests {
|
|||||||
.finish();
|
.finish();
|
||||||
req.payload_mut().unread_data(Bytes::from_static(b"hello=world"));
|
req.payload_mut().unread_data(Bytes::from_static(b"hello=world"));
|
||||||
|
|
||||||
match Form::<Info>::from_request(&req).poll().unwrap() {
|
let mut cfg = FormConfig::default();
|
||||||
|
cfg.limit(4096);
|
||||||
|
match Form::<Info>::from_request(&req, &cfg).poll().unwrap() {
|
||||||
Async::Ready(s) => {
|
Async::Ready(s) => {
|
||||||
assert_eq!(s.hello, "world");
|
assert_eq!(s.hello, "world");
|
||||||
},
|
},
|
||||||
@ -390,7 +445,7 @@ mod tests {
|
|||||||
let (router, _) = Router::new("", ServerSettings::default(), routes);
|
let (router, _) = Router::new("", ServerSettings::default(), routes);
|
||||||
assert!(router.recognize(&mut req).is_some());
|
assert!(router.recognize(&mut req).is_some());
|
||||||
|
|
||||||
match Path::<MyStruct>::from_request(&req).poll().unwrap() {
|
match Path::<MyStruct>::from_request(&req, &()).poll().unwrap() {
|
||||||
Async::Ready(s) => {
|
Async::Ready(s) => {
|
||||||
assert_eq!(s.key, "name");
|
assert_eq!(s.key, "name");
|
||||||
assert_eq!(s.value, "user1");
|
assert_eq!(s.value, "user1");
|
||||||
@ -398,7 +453,7 @@ mod tests {
|
|||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
|
|
||||||
match Path::<(String, String)>::from_request(&req).poll().unwrap() {
|
match Path::<(String, String)>::from_request(&req, &()).poll().unwrap() {
|
||||||
Async::Ready(s) => {
|
Async::Ready(s) => {
|
||||||
assert_eq!(s.0, "name");
|
assert_eq!(s.0, "name");
|
||||||
assert_eq!(s.1, "user1");
|
assert_eq!(s.1, "user1");
|
||||||
@ -406,7 +461,7 @@ mod tests {
|
|||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
|
|
||||||
match Query::<Id>::from_request(&req).poll().unwrap() {
|
match Query::<Id>::from_request(&req, &()).poll().unwrap() {
|
||||||
Async::Ready(s) => {
|
Async::Ready(s) => {
|
||||||
assert_eq!(s.id, "test");
|
assert_eq!(s.id, "test");
|
||||||
},
|
},
|
||||||
@ -416,7 +471,7 @@ mod tests {
|
|||||||
let mut req = TestRequest::with_uri("/name/32/").finish();
|
let mut req = TestRequest::with_uri("/name/32/").finish();
|
||||||
assert!(router.recognize(&mut req).is_some());
|
assert!(router.recognize(&mut req).is_some());
|
||||||
|
|
||||||
match Path::<Test2>::from_request(&req).poll().unwrap() {
|
match Path::<Test2>::from_request(&req, &()).poll().unwrap() {
|
||||||
Async::Ready(s) => {
|
Async::Ready(s) => {
|
||||||
assert_eq!(s.as_ref().key, "name");
|
assert_eq!(s.as_ref().key, "name");
|
||||||
assert_eq!(s.value, 32);
|
assert_eq!(s.value, 32);
|
||||||
@ -424,7 +479,7 @@ mod tests {
|
|||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
|
|
||||||
match Path::<(String, u8)>::from_request(&req).poll().unwrap() {
|
match Path::<(String, u8)>::from_request(&req, &()).poll().unwrap() {
|
||||||
Async::Ready(s) => {
|
Async::Ready(s) => {
|
||||||
assert_eq!(s.0, "name");
|
assert_eq!(s.0, "name");
|
||||||
assert_eq!(s.1, 32);
|
assert_eq!(s.1, 32);
|
||||||
@ -432,7 +487,7 @@ mod tests {
|
|||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
|
|
||||||
match Path::<Vec<String>>::from_request(&req).poll().unwrap() {
|
match Path::<Vec<String>>::from_request(&req, &()).poll().unwrap() {
|
||||||
Async::Ready(s) => {
|
Async::Ready(s) => {
|
||||||
assert_eq!(s.into_inner(), vec!["name".to_owned(), "32".to_owned()]);
|
assert_eq!(s.into_inner(), vec!["name".to_owned(), "32".to_owned()]);
|
||||||
},
|
},
|
||||||
@ -451,7 +506,7 @@ mod tests {
|
|||||||
let mut req = TestRequest::with_uri("/32/").finish();
|
let mut req = TestRequest::with_uri("/32/").finish();
|
||||||
assert!(router.recognize(&mut req).is_some());
|
assert!(router.recognize(&mut req).is_some());
|
||||||
|
|
||||||
match Path::<i8>::from_request(&req).poll().unwrap() {
|
match Path::<i8>::from_request(&req, &()).poll().unwrap() {
|
||||||
Async::Ready(s) => {
|
Async::Ready(s) => {
|
||||||
assert_eq!(s.into_inner(), 32);
|
assert_eq!(s.into_inner(), 32);
|
||||||
},
|
},
|
||||||
|
@ -37,9 +37,14 @@ pub trait Responder {
|
|||||||
/// Types that implement this trait can be used with `Route::with()` method.
|
/// Types that implement this trait can be used with `Route::with()` method.
|
||||||
pub trait FromRequest<S>: Sized where S: 'static
|
pub trait FromRequest<S>: Sized where S: 'static
|
||||||
{
|
{
|
||||||
|
/// Configuration for conversion process
|
||||||
|
type Config: Default;
|
||||||
|
|
||||||
|
/// Future that resolves to a Self
|
||||||
type Result: Future<Item=Self, Error=Error>;
|
type Result: Future<Item=Self, Error=Error>;
|
||||||
|
|
||||||
fn from_request(req: &HttpRequest<S>) -> Self::Result;
|
/// Convert request to a Self
|
||||||
|
fn from_request(req: &HttpRequest<S>, cfg: &Self::Config) -> Self::Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Combines two different responder types into a single type
|
/// Combines two different responder types into a single type
|
||||||
@ -433,10 +438,11 @@ impl<S> Deref for State<S> {
|
|||||||
|
|
||||||
impl<S: 'static> FromRequest<S> for State<S>
|
impl<S: 'static> FromRequest<S> for State<S>
|
||||||
{
|
{
|
||||||
|
type Config = ();
|
||||||
type Result = FutureResult<Self, Error>;
|
type Result = FutureResult<Self, Error>;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from_request(req: &HttpRequest<S>) -> Self::Result {
|
fn from_request(req: &HttpRequest<S>, _: &Self::Config) -> Self::Result {
|
||||||
ok(State(req.clone()))
|
ok(State(req.clone()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -494,10 +494,11 @@ impl<S> Clone for HttpRequest<S> {
|
|||||||
|
|
||||||
impl<S: 'static> FromRequest<S> for HttpRequest<S>
|
impl<S: 'static> FromRequest<S> for HttpRequest<S>
|
||||||
{
|
{
|
||||||
|
type Config = ();
|
||||||
type Result = FutureResult<Self, Error>;
|
type Result = FutureResult<Self, Error>;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from_request(req: &HttpRequest<S>) -> Self::Result {
|
fn from_request(req: &HttpRequest<S>, _: &Self::Config) -> Self::Result {
|
||||||
result(Ok(req.clone()))
|
result(Ok(req.clone()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
55
src/json.rs
55
src/json.rs
@ -110,17 +110,64 @@ impl<T: Serialize> Responder for Json<T> {
|
|||||||
impl<T, S> FromRequest<S> for Json<T>
|
impl<T, S> FromRequest<S> for Json<T>
|
||||||
where T: DeserializeOwned + 'static, S: 'static
|
where T: DeserializeOwned + 'static, S: 'static
|
||||||
{
|
{
|
||||||
|
type Config = JsonConfig;
|
||||||
type Result = Box<Future<Item=Self, Error=Error>>;
|
type Result = Box<Future<Item=Self, Error=Error>>;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from_request(req: &HttpRequest<S>) -> Self::Result {
|
fn from_request(req: &HttpRequest<S>, cfg: &Self::Config) -> Self::Result {
|
||||||
Box::new(
|
Box::new(
|
||||||
JsonBody::new(req.clone())
|
JsonBody::new(req.clone())
|
||||||
|
.limit(cfg.limit)
|
||||||
.from_err()
|
.from_err()
|
||||||
.map(Json))
|
.map(Json))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Json extractor configuration
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # extern crate actix_web;
|
||||||
|
/// #[macro_use] extern crate serde_derive;
|
||||||
|
/// use actix_web::{App, Json, Result, http};
|
||||||
|
///
|
||||||
|
/// #[derive(Deserialize)]
|
||||||
|
/// struct Info {
|
||||||
|
/// username: String,
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// /// deserialize `Info` from request's body, max payload size is 4kb
|
||||||
|
/// fn index(info: Json<Info>) -> Result<String> {
|
||||||
|
/// Ok(format!("Welcome {}!", info.username))
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// fn main() {
|
||||||
|
/// let app = App::new().resource(
|
||||||
|
/// "/index.html", |r| {
|
||||||
|
/// r.method(http::Method::POST)
|
||||||
|
/// .with(index)
|
||||||
|
/// .limit(4096);} // <- change json extractor configuration
|
||||||
|
/// );
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
pub struct JsonConfig {
|
||||||
|
limit: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JsonConfig {
|
||||||
|
|
||||||
|
/// Change max size of payload. By default max size is 256Kb
|
||||||
|
pub fn limit(&mut self, limit: usize) -> &mut Self {
|
||||||
|
self.limit = limit;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for JsonConfig {
|
||||||
|
fn default() -> Self {
|
||||||
|
JsonConfig{limit: 262_144}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Request payload json parser that resolves to a deserialized `T` value.
|
/// Request payload json parser that resolves to a deserialized `T` value.
|
||||||
///
|
///
|
||||||
/// Returns error:
|
/// Returns error:
|
||||||
@ -231,7 +278,7 @@ mod tests {
|
|||||||
use http::header;
|
use http::header;
|
||||||
use futures::Async;
|
use futures::Async;
|
||||||
|
|
||||||
use with::With;
|
use with::{With, ExtractorConfig};
|
||||||
use handler::Handler;
|
use handler::Handler;
|
||||||
|
|
||||||
impl PartialEq for JsonPayloadError {
|
impl PartialEq for JsonPayloadError {
|
||||||
@ -295,7 +342,9 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_with_json() {
|
fn test_with_json() {
|
||||||
let mut handler = With::new(|data: Json<MyObject>| data);
|
let mut cfg = ExtractorConfig::<_, Json<MyObject>>::default();
|
||||||
|
cfg.limit(4096);
|
||||||
|
let mut handler = With::new(|data: Json<MyObject>| {data}, cfg);
|
||||||
|
|
||||||
let req = HttpRequest::default();
|
let req = HttpRequest::default();
|
||||||
let err = handler.handle(req).as_response().unwrap().error().is_some();
|
let err = handler.handle(req).as_response().unwrap().error().is_some();
|
||||||
|
@ -177,9 +177,10 @@ pub mod dev {
|
|||||||
|
|
||||||
pub use body::BodyStream;
|
pub use body::BodyStream;
|
||||||
pub use context::Drain;
|
pub use context::Drain;
|
||||||
pub use json::JsonBody;
|
pub use json::{JsonBody, JsonConfig};
|
||||||
pub use info::ConnectionInfo;
|
pub use info::ConnectionInfo;
|
||||||
pub use handler::{Handler, Reply};
|
pub use handler::{Handler, Reply};
|
||||||
|
pub use extractor::{FormConfig};
|
||||||
pub use route::Route;
|
pub use route::Route;
|
||||||
pub use router::{Router, Resource, ResourceType};
|
pub use router::{Router, Resource, ResourceType};
|
||||||
pub use resource::ResourceHandler;
|
pub use resource::ResourceHandler;
|
||||||
|
@ -144,7 +144,7 @@ impl<S: 'static> ResourceHandler<S> {
|
|||||||
T: FromRequest<S> + 'static,
|
T: FromRequest<S> + 'static,
|
||||||
{
|
{
|
||||||
self.routes.push(Route::default());
|
self.routes.push(Route::default());
|
||||||
self.routes.last_mut().unwrap().with(handler)
|
self.routes.last_mut().unwrap().with(handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Register a resource middleware
|
/// Register a resource middleware
|
||||||
|
22
src/route.rs
22
src/route.rs
@ -11,7 +11,7 @@ use handler::{Reply, ReplyItem, Handler, FromRequest,
|
|||||||
use middleware::{Middleware, Response as MiddlewareResponse, Started as MiddlewareStarted};
|
use middleware::{Middleware, Response as MiddlewareResponse, Started as MiddlewareStarted};
|
||||||
use httprequest::HttpRequest;
|
use httprequest::HttpRequest;
|
||||||
use httpresponse::HttpResponse;
|
use httpresponse::HttpResponse;
|
||||||
use with::{With, With2, With3};
|
use with::{With, With2, With3, ExtractorConfig};
|
||||||
|
|
||||||
/// Resource route definition
|
/// Resource route definition
|
||||||
///
|
///
|
||||||
@ -127,12 +127,14 @@ impl<S: 'static> Route<S> {
|
|||||||
/// |r| r.method(http::Method::GET).with(index)); // <- use `with` extractor
|
/// |r| r.method(http::Method::GET).with(index)); // <- use `with` extractor
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn with<T, F, R>(&mut self, handler: F)
|
pub fn with<T, F, R>(&mut self, handler: F) -> ExtractorConfig<S, T>
|
||||||
where F: Fn(T) -> R + 'static,
|
where F: Fn(T) -> R + 'static,
|
||||||
R: Responder + 'static,
|
R: Responder + 'static,
|
||||||
T: FromRequest<S> + 'static,
|
T: FromRequest<S> + 'static,
|
||||||
{
|
{
|
||||||
self.h(With::new(handler))
|
let cfg = ExtractorConfig::default();
|
||||||
|
self.h(With::new(handler, Clone::clone(&cfg)));
|
||||||
|
cfg
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set handler function, function has to accept two request extractors.
|
/// Set handler function, function has to accept two request extractors.
|
||||||
@ -166,23 +168,33 @@ impl<S: 'static> Route<S> {
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn with2<T1, T2, F, R>(&mut self, handler: F)
|
pub fn with2<T1, T2, F, R>(&mut self, handler: F)
|
||||||
|
-> (ExtractorConfig<S, T1>, ExtractorConfig<S, T2>)
|
||||||
where F: Fn(T1, T2) -> R + 'static,
|
where F: Fn(T1, T2) -> R + 'static,
|
||||||
R: Responder + 'static,
|
R: Responder + 'static,
|
||||||
T1: FromRequest<S> + 'static,
|
T1: FromRequest<S> + 'static,
|
||||||
T2: FromRequest<S> + 'static,
|
T2: FromRequest<S> + 'static,
|
||||||
{
|
{
|
||||||
self.h(With2::new(handler))
|
let cfg1 = ExtractorConfig::default();
|
||||||
|
let cfg2 = ExtractorConfig::default();
|
||||||
|
self.h(With2::new(handler, Clone::clone(&cfg1), Clone::clone(&cfg2)));
|
||||||
|
(cfg1, cfg2)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set handler function, function has to accept three request extractors.
|
/// Set handler function, function has to accept three request extractors.
|
||||||
pub fn with3<T1, T2, T3, F, R>(&mut self, handler: F)
|
pub fn with3<T1, T2, T3, F, R>(&mut self, handler: F)
|
||||||
|
-> (ExtractorConfig<S, T1>, ExtractorConfig<S, T2>, ExtractorConfig<S, T3>)
|
||||||
where F: Fn(T1, T2, T3) -> R + 'static,
|
where F: Fn(T1, T2, T3) -> R + 'static,
|
||||||
R: Responder + 'static,
|
R: Responder + 'static,
|
||||||
T1: FromRequest<S> + 'static,
|
T1: FromRequest<S> + 'static,
|
||||||
T2: FromRequest<S> + 'static,
|
T2: FromRequest<S> + 'static,
|
||||||
T3: FromRequest<S> + 'static,
|
T3: FromRequest<S> + 'static,
|
||||||
{
|
{
|
||||||
self.h(With3::new(handler))
|
let cfg1 = ExtractorConfig::default();
|
||||||
|
let cfg2 = ExtractorConfig::default();
|
||||||
|
let cfg3 = ExtractorConfig::default();
|
||||||
|
self.h(With3::new(
|
||||||
|
handler, Clone::clone(&cfg1), Clone::clone(&cfg2), Clone::clone(&cfg3)));
|
||||||
|
(cfg1, cfg2, cfg3)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -351,8 +351,8 @@ impl<S: 'static> TestApp<S> {
|
|||||||
|
|
||||||
/// Register resource. This method is similar
|
/// Register resource. This method is similar
|
||||||
/// to `App::resource()` method.
|
/// to `App::resource()` method.
|
||||||
pub fn resource<F>(&mut self, path: &str, f: F) -> &mut TestApp<S>
|
pub fn resource<F, R>(&mut self, path: &str, f: F) -> &mut TestApp<S>
|
||||||
where F: FnOnce(&mut ResourceHandler<S>) + 'static
|
where F: FnOnce(&mut ResourceHandler<S>) -> R + 'static
|
||||||
{
|
{
|
||||||
self.app = Some(self.app.take().unwrap().resource(path, f));
|
self.app = Some(self.app.take().unwrap().resource(path, f));
|
||||||
self
|
self
|
||||||
|
121
src/with.rs
121
src/with.rs
@ -1,6 +1,7 @@
|
|||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::cell::UnsafeCell;
|
use std::cell::UnsafeCell;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
use std::ops::{Deref, DerefMut};
|
||||||
use futures::{Async, Future, Poll};
|
use futures::{Async, Future, Poll};
|
||||||
|
|
||||||
use error::Error;
|
use error::Error;
|
||||||
@ -8,19 +9,55 @@ use handler::{Handler, FromRequest, Reply, ReplyItem, Responder};
|
|||||||
use httprequest::HttpRequest;
|
use httprequest::HttpRequest;
|
||||||
use httpresponse::HttpResponse;
|
use httpresponse::HttpResponse;
|
||||||
|
|
||||||
|
pub struct ExtractorConfig<S: 'static, T: FromRequest<S>> {
|
||||||
|
cfg: Rc<UnsafeCell<T::Config>>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: 'static, T: FromRequest<S>> Default for ExtractorConfig<S, T> {
|
||||||
|
fn default() -> Self {
|
||||||
|
ExtractorConfig { cfg: Rc::new(UnsafeCell::new(T::Config::default())) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: 'static, T: FromRequest<S>> Clone for ExtractorConfig<S, T> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
ExtractorConfig { cfg: Rc::clone(&self.cfg) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: 'static, T: FromRequest<S>> AsRef<T::Config> for ExtractorConfig<S, T> {
|
||||||
|
fn as_ref(&self) -> &T::Config {
|
||||||
|
unsafe{&*self.cfg.get()}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: 'static, T: FromRequest<S>> Deref for ExtractorConfig<S, T> {
|
||||||
|
type Target = T::Config;
|
||||||
|
|
||||||
|
fn deref(&self) -> &T::Config {
|
||||||
|
unsafe{&*self.cfg.get()}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: 'static, T: FromRequest<S>> DerefMut for ExtractorConfig<S, T> {
|
||||||
|
fn deref_mut(&mut self) -> &mut T::Config {
|
||||||
|
unsafe{&mut *self.cfg.get()}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct With<T, S, F, R>
|
pub struct With<T, S, F, R>
|
||||||
where F: Fn(T) -> R
|
where F: Fn(T) -> R, T: FromRequest<S>, S: 'static,
|
||||||
{
|
{
|
||||||
hnd: Rc<UnsafeCell<F>>,
|
hnd: Rc<UnsafeCell<F>>,
|
||||||
_t: PhantomData<T>,
|
cfg: ExtractorConfig<S, T>,
|
||||||
_s: PhantomData<S>,
|
_s: PhantomData<S>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, S, F, R> With<T, S, F, R>
|
impl<T, S, F, R> With<T, S, F, R>
|
||||||
where F: Fn(T) -> R,
|
where F: Fn(T) -> R, T: FromRequest<S>, S: 'static,
|
||||||
{
|
{
|
||||||
pub fn new(f: F) -> Self {
|
pub fn new(f: F, cfg: ExtractorConfig<S, T>) -> Self {
|
||||||
With{hnd: Rc::new(UnsafeCell::new(f)), _t: PhantomData, _s: PhantomData}
|
With{cfg, hnd: Rc::new(UnsafeCell::new(f)), _s: PhantomData}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,6 +74,7 @@ impl<T, S, F, R> Handler<S> for With<T, S, F, R>
|
|||||||
req,
|
req,
|
||||||
started: false,
|
started: false,
|
||||||
hnd: Rc::clone(&self.hnd),
|
hnd: Rc::clone(&self.hnd),
|
||||||
|
cfg: self.cfg.clone(),
|
||||||
fut1: None,
|
fut1: None,
|
||||||
fut2: None,
|
fut2: None,
|
||||||
};
|
};
|
||||||
@ -57,6 +95,7 @@ struct WithHandlerFut<T, S, F, R>
|
|||||||
{
|
{
|
||||||
started: bool,
|
started: bool,
|
||||||
hnd: Rc<UnsafeCell<F>>,
|
hnd: Rc<UnsafeCell<F>>,
|
||||||
|
cfg: ExtractorConfig<S, T>,
|
||||||
req: HttpRequest<S>,
|
req: HttpRequest<S>,
|
||||||
fut1: Option<Box<Future<Item=T, Error=Error>>>,
|
fut1: Option<Box<Future<Item=T, Error=Error>>>,
|
||||||
fut2: Option<Box<Future<Item=HttpResponse, Error=Error>>>,
|
fut2: Option<Box<Future<Item=HttpResponse, Error=Error>>>,
|
||||||
@ -78,7 +117,7 @@ impl<T, S, F, R> Future for WithHandlerFut<T, S, F, R>
|
|||||||
|
|
||||||
let item = if !self.started {
|
let item = if !self.started {
|
||||||
self.started = true;
|
self.started = true;
|
||||||
let mut fut = T::from_request(&self.req);
|
let mut fut = T::from_request(&self.req, self.cfg.as_ref());
|
||||||
match fut.poll() {
|
match fut.poll() {
|
||||||
Ok(Async::Ready(item)) => item,
|
Ok(Async::Ready(item)) => item,
|
||||||
Ok(Async::NotReady) => {
|
Ok(Async::NotReady) => {
|
||||||
@ -110,19 +149,23 @@ impl<T, S, F, R> Future for WithHandlerFut<T, S, F, R>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct With2<T1, T2, S, F, R> where F: Fn(T1, T2) -> R
|
pub struct With2<T1, T2, S, F, R>
|
||||||
|
where F: Fn(T1, T2) -> R,
|
||||||
|
T1: FromRequest<S> + 'static, T2: FromRequest<S> + 'static, S: 'static
|
||||||
{
|
{
|
||||||
hnd: Rc<UnsafeCell<F>>,
|
hnd: Rc<UnsafeCell<F>>,
|
||||||
_t1: PhantomData<T1>,
|
cfg1: ExtractorConfig<S, T1>,
|
||||||
_t2: PhantomData<T2>,
|
cfg2: ExtractorConfig<S, T2>,
|
||||||
_s: PhantomData<S>,
|
_s: PhantomData<S>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T1, T2, S, F, R> With2<T1, T2, S, F, R> where F: Fn(T1, T2) -> R
|
impl<T1, T2, S, F, R> With2<T1, T2, S, F, R>
|
||||||
|
where F: Fn(T1, T2) -> R,
|
||||||
|
T1: FromRequest<S> + 'static, T2: FromRequest<S> + 'static, S: 'static
|
||||||
{
|
{
|
||||||
pub fn new(f: F) -> Self {
|
pub fn new(f: F, cfg1: ExtractorConfig<S, T1>, cfg2: ExtractorConfig<S, T2>) -> Self {
|
||||||
With2{hnd: Rc::new(UnsafeCell::new(f)),
|
With2{hnd: Rc::new(UnsafeCell::new(f)),
|
||||||
_t1: PhantomData, _t2: PhantomData, _s: PhantomData}
|
cfg1, cfg2, _s: PhantomData}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,6 +183,8 @@ impl<T1, T2, S, F, R> Handler<S> for With2<T1, T2, S, F, R>
|
|||||||
req,
|
req,
|
||||||
started: false,
|
started: false,
|
||||||
hnd: Rc::clone(&self.hnd),
|
hnd: Rc::clone(&self.hnd),
|
||||||
|
cfg1: self.cfg1.clone(),
|
||||||
|
cfg2: self.cfg2.clone(),
|
||||||
item: None,
|
item: None,
|
||||||
fut1: None,
|
fut1: None,
|
||||||
fut2: None,
|
fut2: None,
|
||||||
@ -162,6 +207,8 @@ struct WithHandlerFut2<T1, T2, S, F, R>
|
|||||||
{
|
{
|
||||||
started: bool,
|
started: bool,
|
||||||
hnd: Rc<UnsafeCell<F>>,
|
hnd: Rc<UnsafeCell<F>>,
|
||||||
|
cfg1: ExtractorConfig<S, T1>,
|
||||||
|
cfg2: ExtractorConfig<S, T2>,
|
||||||
req: HttpRequest<S>,
|
req: HttpRequest<S>,
|
||||||
item: Option<T1>,
|
item: Option<T1>,
|
||||||
fut1: Option<Box<Future<Item=T1, Error=Error>>>,
|
fut1: Option<Box<Future<Item=T1, Error=Error>>>,
|
||||||
@ -186,10 +233,10 @@ impl<T1, T2, S, F, R> Future for WithHandlerFut2<T1, T2, S, F, R>
|
|||||||
|
|
||||||
if !self.started {
|
if !self.started {
|
||||||
self.started = true;
|
self.started = true;
|
||||||
let mut fut = T1::from_request(&self.req);
|
let mut fut = T1::from_request(&self.req, self.cfg1.as_ref());
|
||||||
match fut.poll() {
|
match fut.poll() {
|
||||||
Ok(Async::Ready(item1)) => {
|
Ok(Async::Ready(item1)) => {
|
||||||
let mut fut = T2::from_request(&self.req);
|
let mut fut = T2::from_request(&self.req,self.cfg2.as_ref());
|
||||||
match fut.poll() {
|
match fut.poll() {
|
||||||
Ok(Async::Ready(item2)) => {
|
Ok(Async::Ready(item2)) => {
|
||||||
let hnd: &mut F = unsafe{&mut *self.hnd.get()};
|
let hnd: &mut F = unsafe{&mut *self.hnd.get()};
|
||||||
@ -228,7 +275,8 @@ impl<T1, T2, S, F, R> Future for WithHandlerFut2<T1, T2, S, F, R>
|
|||||||
Async::Ready(item) => {
|
Async::Ready(item) => {
|
||||||
self.item = Some(item);
|
self.item = Some(item);
|
||||||
self.fut1.take();
|
self.fut1.take();
|
||||||
self.fut2 = Some(Box::new(T2::from_request(&self.req)));
|
self.fut2 = Some(Box::new(
|
||||||
|
T2::from_request(&self.req, self.cfg2.as_ref())));
|
||||||
},
|
},
|
||||||
Async::NotReady => return Ok(Async::NotReady),
|
Async::NotReady => return Ok(Async::NotReady),
|
||||||
}
|
}
|
||||||
@ -256,21 +304,32 @@ impl<T1, T2, S, F, R> Future for WithHandlerFut2<T1, T2, S, F, R>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct With3<T1, T2, T3, S, F, R> where F: Fn(T1, T2, T3) -> R {
|
pub struct With3<T1, T2, T3, S, F, R>
|
||||||
|
where F: Fn(T1, T2, T3) -> R,
|
||||||
|
T1: FromRequest<S> + 'static,
|
||||||
|
T2: FromRequest<S> + 'static,
|
||||||
|
T3: FromRequest<S> + 'static,
|
||||||
|
S: 'static
|
||||||
|
{
|
||||||
hnd: Rc<UnsafeCell<F>>,
|
hnd: Rc<UnsafeCell<F>>,
|
||||||
_t1: PhantomData<T1>,
|
cfg1: ExtractorConfig<S, T1>,
|
||||||
_t2: PhantomData<T2>,
|
cfg2: ExtractorConfig<S, T2>,
|
||||||
_t3: PhantomData<T3>,
|
cfg3: ExtractorConfig<S, T3>,
|
||||||
_s: PhantomData<S>,
|
_s: PhantomData<S>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl<T1, T2, T3, S, F, R> With3<T1, T2, T3, S, F, R>
|
impl<T1, T2, T3, S, F, R> With3<T1, T2, T3, S, F, R>
|
||||||
where F: Fn(T1, T2, T3) -> R,
|
where F: Fn(T1, T2, T3) -> R,
|
||||||
|
T1: FromRequest<S> + 'static,
|
||||||
|
T2: FromRequest<S> + 'static,
|
||||||
|
T3: FromRequest<S> + 'static,
|
||||||
|
S: 'static
|
||||||
{
|
{
|
||||||
pub fn new(f: F) -> Self {
|
pub fn new(f: F, cfg1: ExtractorConfig<S, T1>,
|
||||||
With3{hnd: Rc::new(UnsafeCell::new(f)),
|
cfg2: ExtractorConfig<S, T2>, cfg3: ExtractorConfig<S, T3>) -> Self
|
||||||
_s: PhantomData, _t1: PhantomData, _t2: PhantomData, _t3: PhantomData}
|
{
|
||||||
|
With3{hnd: Rc::new(UnsafeCell::new(f)), cfg1, cfg2, cfg3, _s: PhantomData}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -288,6 +347,9 @@ impl<T1, T2, T3, S, F, R> Handler<S> for With3<T1, T2, T3, S, F, R>
|
|||||||
let mut fut = WithHandlerFut3{
|
let mut fut = WithHandlerFut3{
|
||||||
req,
|
req,
|
||||||
hnd: Rc::clone(&self.hnd),
|
hnd: Rc::clone(&self.hnd),
|
||||||
|
cfg1: self.cfg1.clone(),
|
||||||
|
cfg2: self.cfg2.clone(),
|
||||||
|
cfg3: self.cfg3.clone(),
|
||||||
started: false,
|
started: false,
|
||||||
item1: None,
|
item1: None,
|
||||||
item2: None,
|
item2: None,
|
||||||
@ -314,6 +376,9 @@ struct WithHandlerFut3<T1, T2, T3, S, F, R>
|
|||||||
{
|
{
|
||||||
hnd: Rc<UnsafeCell<F>>,
|
hnd: Rc<UnsafeCell<F>>,
|
||||||
req: HttpRequest<S>,
|
req: HttpRequest<S>,
|
||||||
|
cfg1: ExtractorConfig<S, T1>,
|
||||||
|
cfg2: ExtractorConfig<S, T2>,
|
||||||
|
cfg3: ExtractorConfig<S, T3>,
|
||||||
started: bool,
|
started: bool,
|
||||||
item1: Option<T1>,
|
item1: Option<T1>,
|
||||||
item2: Option<T2>,
|
item2: Option<T2>,
|
||||||
@ -341,13 +406,13 @@ impl<T1, T2, T3, S, F, R> Future for WithHandlerFut3<T1, T2, T3, S, F, R>
|
|||||||
|
|
||||||
if !self.started {
|
if !self.started {
|
||||||
self.started = true;
|
self.started = true;
|
||||||
let mut fut = T1::from_request(&self.req);
|
let mut fut = T1::from_request(&self.req, self.cfg1.as_ref());
|
||||||
match fut.poll() {
|
match fut.poll() {
|
||||||
Ok(Async::Ready(item1)) => {
|
Ok(Async::Ready(item1)) => {
|
||||||
let mut fut = T2::from_request(&self.req);
|
let mut fut = T2::from_request(&self.req, self.cfg2.as_ref());
|
||||||
match fut.poll() {
|
match fut.poll() {
|
||||||
Ok(Async::Ready(item2)) => {
|
Ok(Async::Ready(item2)) => {
|
||||||
let mut fut = T3::from_request(&self.req);
|
let mut fut = T3::from_request(&self.req, self.cfg3.as_ref());
|
||||||
match fut.poll() {
|
match fut.poll() {
|
||||||
Ok(Async::Ready(item3)) => {
|
Ok(Async::Ready(item3)) => {
|
||||||
let hnd: &mut F = unsafe{&mut *self.hnd.get()};
|
let hnd: &mut F = unsafe{&mut *self.hnd.get()};
|
||||||
@ -395,7 +460,8 @@ impl<T1, T2, T3, S, F, R> Future for WithHandlerFut3<T1, T2, T3, S, F, R>
|
|||||||
Async::Ready(item) => {
|
Async::Ready(item) => {
|
||||||
self.item1 = Some(item);
|
self.item1 = Some(item);
|
||||||
self.fut1.take();
|
self.fut1.take();
|
||||||
self.fut2 = Some(Box::new(T2::from_request(&self.req)));
|
self.fut2 = Some(Box::new(
|
||||||
|
T2::from_request(&self.req, self.cfg2.as_ref())));
|
||||||
},
|
},
|
||||||
Async::NotReady => return Ok(Async::NotReady),
|
Async::NotReady => return Ok(Async::NotReady),
|
||||||
}
|
}
|
||||||
@ -406,7 +472,8 @@ impl<T1, T2, T3, S, F, R> Future for WithHandlerFut3<T1, T2, T3, S, F, R>
|
|||||||
Async::Ready(item) => {
|
Async::Ready(item) => {
|
||||||
self.item2 = Some(item);
|
self.item2 = Some(item);
|
||||||
self.fut2.take();
|
self.fut2.take();
|
||||||
self.fut3 = Some(Box::new(T3::from_request(&self.req)));
|
self.fut3 = Some(Box::new(
|
||||||
|
T3::from_request(&self.req, self.cfg3.as_ref())));
|
||||||
},
|
},
|
||||||
Async::NotReady => return Ok(Async::NotReady),
|
Async::NotReady => return Ok(Async::NotReady),
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user