#![allow(dead_code)] use std::ops::{Deref, DerefMut}; use std::rc::Rc; use std::{fmt, str}; use bytes::Bytes; use encoding::all::UTF_8; use encoding::types::{DecoderTrap, Encoding}; use futures::future::{err, ok, Either, FutureResult}; use futures::{future, Async, Future, IntoFuture, Poll, Stream}; use mime::Mime; use serde::de::{self, DeserializeOwned}; use serde::Serialize; use serde_json; use serde_urlencoded; use actix_http::dev::{JsonBody, MessageBody, UrlEncoded}; use actix_http::error::{ Error, ErrorBadRequest, ErrorNotFound, JsonPayloadError, PayloadError, UrlencodedError, }; use actix_http::http::StatusCode; use actix_http::{Extensions, HttpMessage, Response}; use actix_router::PathDeserializer; use crate::request::HttpRequest; use crate::responder::Responder; use crate::service::ServiceFromRequest; /// Trait implemented by types that can be extracted from request. /// /// Types that implement this trait can be used with `Route` handlers. pub trait FromRequest

: Sized { /// The associated error which can be returned. type Error: Into; /// Future that resolves to a Self type Future: IntoFuture; /// Configuration for the extractor type Config: ExtractorConfig; /// Convert request to a Self fn from_request(req: &mut ServiceFromRequest

) -> Self::Future; } /// Storage for extractor configs #[derive(Default)] pub struct ConfigStorage { pub(crate) storage: Option>, } impl ConfigStorage { pub fn store(&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) {} } #[derive(PartialEq, Eq, PartialOrd, Ord)] /// Extract typed information from the request's path. /// /// ## Example /// /// ```rust /// use actix_web::{web, App}; /// /// /// extract path info from "/{username}/{count}/index.html" url /// /// {username} - deserializes to a String /// /// {count} - - deserializes to a u32 /// fn index(info: web::Path<(String, u32)>) -> String { /// format!("Welcome {}! {}", info.0, info.1) /// } /// /// fn main() { /// let app = App::new().service( /// web::resource("/{username}/{count}/index.html") // <- define path parameters /// .route(web::get().to(index)) // <- register handler with `Path` extractor /// ); /// } /// ``` /// /// It is possible to extract path information to a specific type that /// implements `Deserialize` trait from *serde*. /// /// ```rust /// #[macro_use] extern crate serde_derive; /// use actix_web::{web, App, Error}; /// /// #[derive(Deserialize)] /// struct Info { /// username: String, /// } /// /// /// extract `Info` from a path using serde /// fn index(info: web::Path) -> Result { /// Ok(format!("Welcome {}!", info.username)) /// } /// /// fn main() { /// let app = App::new().service( /// web::resource("/{username}/index.html") // <- define path parameters /// .route(web::get().to(index)) // <- use handler with Path` extractor /// ); /// } /// ``` pub struct Path { inner: T, } impl AsRef for Path { fn as_ref(&self) -> &T { &self.inner } } impl Deref for Path { type Target = T; fn deref(&self) -> &T { &self.inner } } impl DerefMut for Path { fn deref_mut(&mut self) -> &mut T { &mut self.inner } } impl Path { /// Deconstruct to an inner value pub fn into_inner(self) -> T { self.inner } /// Extract path information from a request pub fn extract(req: &HttpRequest) -> Result, de::value::Error> where T: DeserializeOwned, { de::Deserialize::deserialize(PathDeserializer::new(req.match_info())) .map(|inner| Path { inner }) } } impl From for Path { fn from(inner: T) -> Path { Path { inner } } } /// Extract typed information from the request's path. /// /// ## Example /// /// ```rust /// use actix_web::{web, App}; /// /// /// extract path info from "/{username}/{count}/index.html" url /// /// {username} - deserializes to a String /// /// {count} - - deserializes to a u32 /// fn index(info: web::Path<(String, u32)>) -> String { /// format!("Welcome {}! {}", info.0, info.1) /// } /// /// fn main() { /// let app = App::new().service( /// web::resource("/{username}/{count}/index.html") // <- define path parameters /// .route(web::get().to(index)) // <- register handler with `Path` extractor /// ); /// } /// ``` /// /// It is possible to extract path information to a specific type that /// implements `Deserialize` trait from *serde*. /// /// ```rust /// #[macro_use] extern crate serde_derive; /// use actix_web::{web, App, Error}; /// /// #[derive(Deserialize)] /// struct Info { /// username: String, /// } /// /// /// extract `Info` from a path using serde /// fn index(info: web::Path) -> Result { /// Ok(format!("Welcome {}!", info.username)) /// } /// /// fn main() { /// let app = App::new().service( /// web::resource("/{username}/index.html") // <- define path parameters /// .route(web::get().to(index)) // <- use handler with Path` extractor /// ); /// } /// ``` impl FromRequest

for Path where T: DeserializeOwned, { type Error = Error; type Future = Result; type Config = (); #[inline] fn from_request(req: &mut ServiceFromRequest

) -> Self::Future { Self::extract(req).map_err(ErrorNotFound) } } impl fmt::Debug for Path { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.inner.fmt(f) } } impl fmt::Display for Path { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.inner.fmt(f) } } #[derive(PartialEq, Eq, PartialOrd, Ord)] /// Extract typed information from from the request's query. /// /// ## Example /// /// ```rust /// #[macro_use] extern crate serde_derive; /// use actix_web::{web, App}; /// /// #[derive(Debug, Deserialize)] /// pub enum ResponseType { /// Token, /// Code /// } /// /// #[derive(Deserialize)] /// pub struct AuthRequest { /// id: u64, /// response_type: ResponseType, /// } /// /// // Use `Query` extractor for query information. /// // This handler get called only if request's query contains `username` field /// // The correct request for this handler would be `/index.html?id=64&response_type=Code"` /// fn index(info: web::Query) -> String { /// format!("Authorization request for client with id={} and type={:?}!", info.id, info.response_type) /// } /// /// fn main() { /// let app = App::new().service( /// web::resource("/index.html").route(web::get().to(index))); // <- use `Query` extractor /// } /// ``` pub struct Query(T); impl Deref for Query { type Target = T; fn deref(&self) -> &T { &self.0 } } impl DerefMut for Query { fn deref_mut(&mut self) -> &mut T { &mut self.0 } } impl Query { /// Deconstruct to a inner value pub fn into_inner(self) -> T { self.0 } } /// Extract typed information from from the request's query. /// /// ## Example /// /// ```rust /// #[macro_use] extern crate serde_derive; /// use actix_web::{web, App}; /// /// #[derive(Debug, Deserialize)] /// pub enum ResponseType { /// Token, /// Code /// } /// /// #[derive(Deserialize)] /// pub struct AuthRequest { /// id: u64, /// response_type: ResponseType, /// } /// /// // Use `Query` extractor for query information. /// // This handler get called only if request's query contains `username` field /// // The correct request for this handler would be `/index.html?id=64&response_type=Code"` /// fn index(info: web::Query) -> String { /// format!("Authorization request for client with id={} and type={:?}!", info.id, info.response_type) /// } /// /// fn main() { /// let app = App::new().service( /// web::resource("/index.html") /// .route(web::get().to(index))); // <- use `Query` extractor /// } /// ``` impl FromRequest

for Query where T: de::DeserializeOwned, { type Error = Error; type Future = Result; type Config = (); #[inline] fn from_request(req: &mut ServiceFromRequest

) -> Self::Future { serde_urlencoded::from_str::(req.query_string()) .map(|val| Ok(Query(val))) .unwrap_or_else(|e| Err(e.into())) } } impl fmt::Debug for Query { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.0.fmt(f) } } impl fmt::Display for Query { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.0.fmt(f) } } #[derive(PartialEq, Eq, PartialOrd, Ord)] /// Extract typed information from the request's body. /// /// To extract typed information from request's body, the type `T` must /// implement the `Deserialize` trait from *serde*. /// /// [**FormConfig**](struct.FormConfig.html) allows to configure extraction /// process. /// /// ## Example /// /// ```rust /// # extern crate actix_web; /// #[macro_use] extern crate serde_derive; /// use actix_web::{web, App}; /// /// #[derive(Deserialize)] /// struct FormData { /// username: String, /// } /// /// /// Extract form data using serde. /// /// This handler get called only if content type is *x-www-form-urlencoded* /// /// and content of the request could be deserialized to a `FormData` struct /// fn index(form: web::Form) -> String { /// format!("Welcome {}!", form.username) /// } /// # fn main() {} /// ``` pub struct Form(pub T); impl Form { /// Deconstruct to an inner value pub fn into_inner(self) -> T { self.0 } } impl Deref for Form { type Target = T; fn deref(&self) -> &T { &self.0 } } impl DerefMut for Form { fn deref_mut(&mut self) -> &mut T { &mut self.0 } } impl FromRequest

for Form where T: DeserializeOwned + 'static, P: Stream + 'static, { type Error = Error; type Future = Box>; type Config = FormConfig; #[inline] fn from_request(req: &mut ServiceFromRequest

) -> Self::Future { let req2 = req.clone(); let cfg = req.load_config::(); let limit = cfg.limit; let err = Rc::clone(&cfg.ehandler); Box::new( UrlEncoded::new(req) .limit(limit) .map_err(move |e| (*err)(e, &req2)) .map(Form), ) } } impl fmt::Debug for Form { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.0.fmt(f) } } impl fmt::Display for Form { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.0.fmt(f) } } /// Form extractor configuration /// /// ```rust /// #[macro_use] extern crate serde_derive; /// use actix_web::{web, App, Result}; /// /// #[derive(Deserialize)] /// struct FormData { /// username: String, /// } /// /// /// Extract form data using serde. /// /// Custom configuration is used for this handler, max payload size is 4k /// fn index(form: web::Form) -> Result { /// Ok(format!("Welcome {}!", form.username)) /// } /// /// fn main() { /// let app = App::new().service( /// web::resource("/index.html") /// .route(web::get() /// // change `Form` extractor configuration /// .config(web::FormConfig::default().limit(4097)) /// .to(index)) /// ); /// } /// ``` #[derive(Clone)] pub struct FormConfig { limit: usize, ehandler: Rc Error>, } impl FormConfig { /// Change max size of payload. By default max size is 256Kb pub fn limit(mut self, limit: usize) -> Self { self.limit = limit; self } /// Set custom error handler pub fn error_handler(mut self, f: F) -> Self where F: Fn(UrlencodedError, &HttpRequest) -> Error + 'static, { self.ehandler = Rc::new(f); self } } impl ExtractorConfig for FormConfig {} impl Default for FormConfig { fn default() -> Self { FormConfig { limit: 262_144, ehandler: Rc::new(|e, _| e.into()), } } } /// Json helper /// /// Json can be used for two different purpose. First is for json response /// generation and second is for extracting typed information from request's /// payload. /// /// To extract typed information from request's body, the type `T` must /// implement the `Deserialize` trait from *serde*. /// /// [**JsonConfig**](struct.JsonConfig.html) allows to configure extraction /// process. /// /// ## Example /// /// ```rust /// #[macro_use] extern crate serde_derive; /// use actix_web::{web, App}; /// /// #[derive(Deserialize)] /// struct Info { /// username: String, /// } /// /// /// deserialize `Info` from request's body /// fn index(info: web::Json) -> String { /// format!("Welcome {}!", info.username) /// } /// /// fn main() { /// let app = App::new().service( /// web::resource("/index.html").route( /// web::post().to(index)) /// ); /// } /// ``` /// /// The `Json` type allows you to respond with well-formed JSON data: simply /// return a value of type Json where T is the type of a structure /// to serialize into *JSON*. The type `T` must implement the `Serialize` /// trait from *serde*. /// /// ```rust /// # #[macro_use] extern crate serde_derive; /// # use actix_web::*; /// # /// #[derive(Serialize)] /// struct MyObj { /// name: String, /// } /// /// fn index(req: HttpRequest) -> Result> { /// Ok(web::Json(MyObj { /// name: req.match_info().get("name").unwrap().to_string(), /// })) /// } /// # fn main() {} /// ``` pub struct Json(pub T); impl Json { /// Deconstruct to an inner value pub fn into_inner(self) -> T { self.0 } } impl Deref for Json { type Target = T; fn deref(&self) -> &T { &self.0 } } impl DerefMut for Json { fn deref_mut(&mut self) -> &mut T { &mut self.0 } } impl fmt::Debug for Json where T: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "Json: {:?}", self.0) } } impl fmt::Display for Json where T: fmt::Display, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) } } impl Responder for Json { type Error = Error; type Future = Result; fn respond_to(self, _: &HttpRequest) -> Self::Future { let body = match serde_json::to_string(&self.0) { Ok(body) => body, Err(e) => return Err(e.into()), }; Ok(Response::build(StatusCode::OK) .content_type("application/json") .body(body)) } } /// Json extractor. Allow to extract typed information from request's /// payload. /// /// To extract typed information from request's body, the type `T` must /// implement the `Deserialize` trait from *serde*. /// /// [**JsonConfig**](struct.JsonConfig.html) allows to configure extraction /// process. /// /// ## Example /// /// ```rust /// #[macro_use] extern crate serde_derive; /// use actix_web::{web, App}; /// /// #[derive(Deserialize)] /// struct Info { /// username: String, /// } /// /// /// deserialize `Info` from request's body /// fn index(info: web::Json) -> String { /// format!("Welcome {}!", info.username) /// } /// /// fn main() { /// let app = App::new().service( /// web::resource("/index.html").route( /// web::post().to(index)) /// ); /// } /// ``` impl FromRequest

for Json where T: DeserializeOwned + 'static, P: Stream + 'static, { type Error = Error; type Future = Box>; type Config = JsonConfig; #[inline] fn from_request(req: &mut ServiceFromRequest

) -> Self::Future { let req2 = req.clone(); let cfg = req.load_config::(); let limit = cfg.limit; let err = Rc::clone(&cfg.ehandler); Box::new( JsonBody::new(req) .limit(limit) .map_err(move |e| (*err)(e, &req2)) .map(Json), ) } } /// Json extractor configuration /// /// ```rust /// #[macro_use] extern crate serde_derive; /// use actix_web::{error, web, App, HttpResponse}; /// /// #[derive(Deserialize)] /// struct Info { /// username: String, /// } /// /// /// deserialize `Info` from request's body, max payload size is 4kb /// fn index(info: web::Json) -> String { /// format!("Welcome {}!", info.username) /// } /// /// fn main() { /// let app = App::new().service( /// web::resource("/index.html").route( /// web::post().config( /// // change json extractor configuration /// web::JsonConfig::default().limit(4096) /// .error_handler(|err, req| { // <- create custom error response /// error::InternalError::from_response( /// err, HttpResponse::Conflict().finish()).into() /// })) /// .to(index)) /// ); /// } /// ``` #[derive(Clone)] pub struct JsonConfig { limit: usize, ehandler: Rc Error>, } impl JsonConfig { /// Change max size of payload. By default max size is 256Kb pub fn limit(mut self, limit: usize) -> Self { self.limit = limit; self } /// Set custom error handler pub fn error_handler(mut self, f: F) -> Self where F: Fn(JsonPayloadError, &HttpRequest) -> Error + 'static, { self.ehandler = Rc::new(f); self } } impl ExtractorConfig for JsonConfig {} impl Default for JsonConfig { fn default() -> Self { JsonConfig { limit: 262_144, ehandler: Rc::new(|e, _| e.into()), } } } /// Payload extractor returns request 's payload stream. /// /// ## Example /// /// ```rust /// use futures::{Future, Stream}; /// use actix_web::{web, error, App, Error, HttpResponse}; /// /// /// extract binary data from request /// fn index

(body: web::Payload

) -> impl Future /// where /// P: Stream /// { /// body.map_err(Error::from) /// .fold(web::BytesMut::new(), move |mut body, chunk| { /// body.extend_from_slice(&chunk); /// Ok::<_, Error>(body) /// }) /// .and_then(|body| { /// format!("Body {:?}!", body); /// Ok(HttpResponse::Ok().finish()) /// }) /// } /// /// fn main() { /// let app = App::new().service( /// web::resource("/index.html").route( /// web::get().to_async(index)) /// ); /// } /// ``` pub struct Payload(crate::dev::Payload); impl Stream for Payload where T: Stream, { type Item = Bytes; type Error = PayloadError; #[inline] fn poll(&mut self) -> Poll, PayloadError> { self.0.poll() } } /// Get request's payload stream /// /// ## Example /// /// ```rust /// use futures::{Future, Stream}; /// use actix_web::{web, error, App, Error, HttpResponse}; /// /// /// extract binary data from request /// fn index

(body: web::Payload

) -> impl Future /// where /// P: Stream /// { /// body.map_err(Error::from) /// .fold(web::BytesMut::new(), move |mut body, chunk| { /// body.extend_from_slice(&chunk); /// Ok::<_, Error>(body) /// }) /// .and_then(|body| { /// format!("Body {:?}!", body); /// Ok(HttpResponse::Ok().finish()) /// }) /// } /// /// fn main() { /// let app = App::new().service( /// web::resource("/index.html").route( /// web::get().to_async(index)) /// ); /// } /// ``` impl

FromRequest

for Payload

where P: Stream, { type Error = Error; type Future = Result, Error>; type Config = (); #[inline] fn from_request(req: &mut ServiceFromRequest

) -> Self::Future { Ok(Payload(req.take_payload())) } } /// Request binary data from a request's payload. /// /// Loads request's payload and construct Bytes instance. /// /// [**PayloadConfig**](struct.PayloadConfig.html) allows to configure /// extraction process. /// /// ## Example /// /// ```rust /// use bytes::Bytes; /// use actix_web::{web, App}; /// /// /// extract binary data from request /// fn index(body: Bytes) -> String { /// format!("Body {:?}!", body) /// } /// /// fn main() { /// let app = App::new().service( /// web::resource("/index.html").route( /// web::get().to(index)) /// ); /// } /// ``` impl

FromRequest

for Bytes where P: Stream + 'static, { type Error = Error; type Future = Either>, FutureResult>; type Config = PayloadConfig; #[inline] fn from_request(req: &mut ServiceFromRequest

) -> Self::Future { let cfg = req.load_config::(); if let Err(e) = cfg.check_mimetype(req) { return Either::B(err(e)); } let limit = cfg.limit; Either::A(Box::new(MessageBody::new(req).limit(limit).from_err())) } } /// Extract text information from a request's body. /// /// Text extractor automatically decode body according to the request's charset. /// /// [**PayloadConfig**](struct.PayloadConfig.html) allows to configure /// extraction process. /// /// ## Example /// /// ```rust /// use actix_web::{web, App}; /// /// /// extract text data from request /// fn index(text: String) -> String { /// format!("Body {}!", text) /// } /// /// fn main() { /// let app = App::new().service( /// web::resource("/index.html").route( /// web::get() /// .config(web::PayloadConfig::new(4096)) // <- limit size of the payload /// .to(index)) // <- register handler with extractor params /// ); /// } /// ``` impl

FromRequest

for String where P: Stream + 'static, { type Error = Error; type Future = Either>, FutureResult>; type Config = PayloadConfig; #[inline] fn from_request(req: &mut ServiceFromRequest

) -> Self::Future { let cfg = req.load_config::(); // check content-type if let Err(e) = cfg.check_mimetype(req) { return Either::B(err(e)); } // check charset let encoding = match req.encoding() { Ok(enc) => enc, Err(e) => return Either::B(err(e.into())), }; let limit = cfg.limit; Either::A(Box::new( MessageBody::new(req) .limit(limit) .from_err() .and_then(move |body| { let enc: *const Encoding = encoding as *const Encoding; if enc == UTF_8 { Ok(str::from_utf8(body.as_ref()) .map_err(|_| ErrorBadRequest("Can not decode body"))? .to_owned()) } else { Ok(encoding .decode(&body, DecoderTrap::Strict) .map_err(|_| ErrorBadRequest("Can not decode body"))?) } }), )) } } /// Optionally extract a field from the request /// /// If the FromRequest for T fails, return None rather than returning an error response /// /// ## Example /// /// ```rust /// # #[macro_use] extern crate serde_derive; /// use actix_web::{web, App, Error, FromRequest, ServiceFromRequest}; /// use actix_web::error::ErrorBadRequest; /// use rand; /// /// #[derive(Debug, Deserialize)] /// struct Thing { /// name: String /// } /// /// impl

FromRequest

for Thing { /// type Error = Error; /// type Future = Result; /// type Config = (); /// /// fn from_request(req: &mut ServiceFromRequest

) -> Self::Future { /// if rand::random() { /// Ok(Thing { name: "thingy".into() }) /// } else { /// Err(ErrorBadRequest("no luck")) /// } /// /// } /// } /// /// /// extract `Thing` from request /// fn index(supplied_thing: Option) -> String { /// match supplied_thing { /// // Puns not intended /// Some(thing) => format!("Got something: {:?}", thing), /// None => format!("No thing!") /// } /// } /// /// fn main() { /// let app = App::new().service( /// web::resource("/users/:first").route( /// web::post().to(index)) /// ); /// } /// ``` impl FromRequest

for Option where T: FromRequest

, T::Future: 'static, { type Error = Error; type Future = Box, Error = Error>>; type Config = T::Config; #[inline] fn from_request(req: &mut ServiceFromRequest

) -> Self::Future { Box::new(T::from_request(req).into_future().then(|r| match r { Ok(v) => future::ok(Some(v)), Err(_) => future::ok(None), })) } } /// Optionally extract a field from the request or extract the Error if unsuccessful /// /// If the `FromRequest` for T fails, inject Err into handler rather than returning an error response /// /// ## Example /// /// ```rust /// # #[macro_use] extern crate serde_derive; /// use actix_web::{web, App, Result, Error, FromRequest, ServiceFromRequest}; /// use actix_web::error::ErrorBadRequest; /// use rand; /// /// #[derive(Debug, Deserialize)] /// struct Thing { /// name: String /// } /// /// impl

FromRequest

for Thing { /// type Error = Error; /// type Future = Result; /// type Config = (); /// /// fn from_request(req: &mut ServiceFromRequest

) -> Self::Future { /// if rand::random() { /// Ok(Thing { name: "thingy".into() }) /// } else { /// Err(ErrorBadRequest("no luck")) /// } /// } /// } /// /// /// extract `Thing` from request /// fn index(supplied_thing: Result) -> String { /// match supplied_thing { /// Ok(thing) => format!("Got thing: {:?}", thing), /// Err(e) => format!("Error extracting thing: {}", e) /// } /// } /// /// fn main() { /// let app = App::new().service( /// web::resource("/users/:first").route(web::post().to(index)) /// ); /// } /// ``` impl FromRequest

for Result where T: FromRequest

, T::Future: 'static, T::Error: 'static, { type Error = Error; type Future = Box, Error = Error>>; type Config = T::Config; #[inline] fn from_request(req: &mut ServiceFromRequest

) -> Self::Future { Box::new(T::from_request(req).into_future().then(|res| match res { Ok(v) => ok(Ok(v)), Err(e) => ok(Err(e)), })) } } /// Payload configuration for request's payload. #[derive(Clone)] pub struct PayloadConfig { limit: usize, mimetype: Option, } 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) -> 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) -> Self { self.mimetype = Some(mt); self } fn check_mimetype

(&self, req: &ServiceFromRequest

) -> Result<(), Error> { // check content-type if let Some(ref mt) = self.mimetype { match req.mime_type() { Ok(Some(ref req_mt)) => { if mt != req_mt { return Err(ErrorBadRequest("Unexpected Content-Type")); } } Ok(None) => { return Err(ErrorBadRequest("Content-Type is expected")); } Err(err) => { return Err(err.into()); } } } Ok(()) } } impl ExtractorConfig for PayloadConfig {} impl Default for PayloadConfig { fn default() -> Self { PayloadConfig { limit: 262_144, mimetype: None, } } } #[doc(hidden)] impl

FromRequest

for () { type Error = Error; type Future = Result<(), Error>; type Config = (); fn from_request(_req: &mut ServiceFromRequest

) -> Self::Future { Ok(()) } } 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 #[doc(hidden)] impl + 'static),+> FromRequest

for ($($T,)+) { type Error = Error; type Future = $fut_type; type Config = ($($T::Config,)+); fn from_request(req: &mut ServiceFromRequest

) -> Self::Future { $fut_type { items: <($(Option<$T>,)+)>::default(), futs: ($($T::from_request(req).into_future(),)+), } } } #[doc(hidden)] pub struct $fut_type),+> { items: ($(Option<$T>,)+), futs: ($(<$T::Future as futures::IntoFuture>::Future,)+), } impl),+> Future for $fut_type { type Item = ($($T,)+); type Error = Error; fn poll(&mut self) -> Poll { let mut ready = true; $( if self.items.$n.is_none() { match self.futs.$n.poll() { Ok(Async::Ready(item)) => { self.items.$n = Some(item); } Ok(Async::NotReady) => ready = false, Err(e) => return Err(e.into()), } } )+ if ready { Ok(Async::Ready( ($(self.items.$n.take().unwrap(),)+) )) } else { Ok(Async::NotReady) } } } }); #[rustfmt::skip] 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)); tuple_from_req!(TupleFromRequest4, (0, A), (1, B), (2, C), (3, D)); tuple_from_req!(TupleFromRequest5, (0, A), (1, B), (2, C), (3, D), (4, E)); tuple_from_req!(TupleFromRequest6, (0, A), (1, B), (2, C), (3, D), (4, E), (5, F)); tuple_from_req!(TupleFromRequest7, (0, A), (1, B), (2, C), (3, D), (4, E), (5, F), (6, G)); tuple_from_req!(TupleFromRequest8, (0, A), (1, B), (2, C), (3, D), (4, E), (5, F), (6, G), (7, H)); tuple_from_req!(TupleFromRequest9, (0, A), (1, B), (2, C), (3, D), (4, E), (5, F), (6, G), (7, H), (8, I)); tuple_from_req!(TupleFromRequest10, (0, A), (1, B), (2, C), (3, D), (4, E), (5, F), (6, G), (7, H), (8, I), (9, J)); } #[cfg(test)] mod tests { use actix_http::http::header; use actix_router::ResourceDef; use bytes::Bytes; use serde_derive::Deserialize; use super::*; use crate::test::{block_on, TestRequest}; #[derive(Deserialize, Debug, PartialEq)] struct Info { hello: String, } #[test] fn test_bytes() { let mut req = TestRequest::with_header(header::CONTENT_LENGTH, "11") .set_payload(Bytes::from_static(b"hello=world")) .to_from(); let s = block_on(Bytes::from_request(&mut req)).unwrap(); assert_eq!(s, Bytes::from_static(b"hello=world")); } #[test] fn test_string() { let mut req = TestRequest::with_header(header::CONTENT_LENGTH, "11") .set_payload(Bytes::from_static(b"hello=world")) .to_from(); let s = block_on(String::from_request(&mut req)).unwrap(); assert_eq!(s, "hello=world"); } #[test] fn test_form() { let mut req = TestRequest::with_header( header::CONTENT_TYPE, "application/x-www-form-urlencoded", ) .header(header::CONTENT_LENGTH, "11") .set_payload(Bytes::from_static(b"hello=world")) .to_from(); let s = block_on(Form::::from_request(&mut req)).unwrap(); assert_eq!(s.hello, "world"); } #[test] fn test_option() { let mut req = TestRequest::with_header( header::CONTENT_TYPE, "application/x-www-form-urlencoded", ) .config(FormConfig::default().limit(4096)) .to_from(); let r = block_on(Option::>::from_request(&mut req)).unwrap(); assert_eq!(r, None); let mut req = TestRequest::with_header( header::CONTENT_TYPE, "application/x-www-form-urlencoded", ) .header(header::CONTENT_LENGTH, "9") .set_payload(Bytes::from_static(b"hello=world")) .to_from(); let r = block_on(Option::>::from_request(&mut req)).unwrap(); assert_eq!( r, Some(Form(Info { hello: "world".into() })) ); let mut req = TestRequest::with_header( header::CONTENT_TYPE, "application/x-www-form-urlencoded", ) .header(header::CONTENT_LENGTH, "9") .set_payload(Bytes::from_static(b"bye=world")) .to_from(); let r = block_on(Option::>::from_request(&mut req)).unwrap(); assert_eq!(r, None); } #[test] fn test_result() { let mut req = TestRequest::with_header( header::CONTENT_TYPE, "application/x-www-form-urlencoded", ) .header(header::CONTENT_LENGTH, "11") .set_payload(Bytes::from_static(b"hello=world")) .to_from(); let r = block_on(Result::, Error>::from_request(&mut req)) .unwrap() .unwrap(); assert_eq!( r, Form(Info { hello: "world".into() }) ); let mut req = TestRequest::with_header( header::CONTENT_TYPE, "application/x-www-form-urlencoded", ) .header(header::CONTENT_LENGTH, "9") .set_payload(Bytes::from_static(b"bye=world")) .to_from(); let r = block_on(Result::, Error>::from_request(&mut req)).unwrap(); assert!(r.is_err()); } #[test] fn test_payload_config() { let req = TestRequest::default().to_from(); let cfg = PayloadConfig::default().mimetype(mime::APPLICATION_JSON); assert!(cfg.check_mimetype(&req).is_err()); let req = TestRequest::with_header( header::CONTENT_TYPE, "application/x-www-form-urlencoded", ) .to_from(); assert!(cfg.check_mimetype(&req).is_err()); let req = TestRequest::with_header(header::CONTENT_TYPE, "application/json").to_from(); assert!(cfg.check_mimetype(&req).is_ok()); } #[derive(Deserialize)] struct MyStruct { key: String, value: String, } #[derive(Deserialize)] struct Id { id: String, } #[derive(Deserialize)] struct Test2 { key: String, value: u32, } #[test] fn test_request_extract() { let mut req = TestRequest::with_uri("/name/user1/?id=test").to_from(); let resource = ResourceDef::new("/{key}/{value}/"); resource.match_path(req.match_info_mut()); let s = Path::::from_request(&mut req).unwrap(); assert_eq!(s.key, "name"); assert_eq!(s.value, "user1"); let s = Path::<(String, String)>::from_request(&mut req).unwrap(); assert_eq!(s.0, "name"); assert_eq!(s.1, "user1"); let s = Query::::from_request(&mut req).unwrap(); assert_eq!(s.id, "test"); let mut req = TestRequest::with_uri("/name/32/").to_from(); let resource = ResourceDef::new("/{key}/{value}/"); resource.match_path(req.match_info_mut()); let s = Path::::from_request(&mut req).unwrap(); assert_eq!(s.as_ref().key, "name"); assert_eq!(s.value, 32); let s = Path::<(String, u8)>::from_request(&mut req).unwrap(); assert_eq!(s.0, "name"); assert_eq!(s.1, 32); let res = Path::>::from_request(&mut req).unwrap(); assert_eq!(res[0], "name".to_owned()); assert_eq!(res[1], "32".to_owned()); } #[test] fn test_extract_path_single() { let resource = ResourceDef::new("/{value}/"); let mut req = TestRequest::with_uri("/32/").to_from(); resource.match_path(req.match_info_mut()); assert_eq!(*Path::::from_request(&mut req).unwrap(), 32); } #[test] fn test_tuple_extract() { let resource = ResourceDef::new("/{key}/{value}/"); let mut req = TestRequest::with_uri("/name/user1/?id=test").to_from(); resource.match_path(req.match_info_mut()); let res = block_on(<(Path<(String, String)>,)>::from_request(&mut req)).unwrap(); assert_eq!((res.0).0, "name"); assert_eq!((res.0).1, "user1"); let res = block_on( <(Path<(String, String)>, Path<(String, String)>)>::from_request(&mut req), ) .unwrap(); assert_eq!((res.0).0, "name"); assert_eq!((res.0).1, "user1"); assert_eq!((res.1).0, "name"); assert_eq!((res.1).1, "user1"); let () = <()>::from_request(&mut req).unwrap(); } }