mirror of
https://github.com/fafhrd91/actix-web
synced 2024-11-27 17:52:56 +01:00
refactor FromRequest trait
This commit is contained in:
parent
3c650ca194
commit
75b213a6f0
@ -14,6 +14,8 @@
|
|||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
* `FromRequest` trait refactoring
|
||||||
|
|
||||||
* Move multipart support to actix-multipart crate
|
* Move multipart support to actix-multipart crate
|
||||||
|
|
||||||
|
|
||||||
|
@ -10,8 +10,8 @@ use std::{cmp, io};
|
|||||||
use actix_service::boxed::{self, BoxedNewService, BoxedService};
|
use actix_service::boxed::{self, BoxedNewService, BoxedService};
|
||||||
use actix_service::{IntoNewService, NewService, Service};
|
use actix_service::{IntoNewService, NewService, Service};
|
||||||
use actix_web::dev::{
|
use actix_web::dev::{
|
||||||
HttpServiceFactory, Payload, ResourceDef, ServiceConfig, ServiceFromRequest,
|
HttpServiceFactory, Payload, ResourceDef, ServiceConfig, ServiceRequest,
|
||||||
ServiceRequest, ServiceResponse,
|
ServiceResponse,
|
||||||
};
|
};
|
||||||
use actix_web::error::{BlockingError, Error, ErrorInternalServerError};
|
use actix_web::error::{BlockingError, Error, ErrorInternalServerError};
|
||||||
use actix_web::http::header::DispositionType;
|
use actix_web::http::header::DispositionType;
|
||||||
@ -551,8 +551,8 @@ impl<P> FromRequest<P> for PathBufWrp {
|
|||||||
type Error = UriSegmentError;
|
type Error = UriSegmentError;
|
||||||
type Future = Result<Self, Self::Error>;
|
type Future = Result<Self, Self::Error>;
|
||||||
|
|
||||||
fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future {
|
fn from_request(req: &HttpRequest, _: &mut Payload<P>) -> Self::Future {
|
||||||
PathBufWrp::get_pathbuf(req.request().match_info().path())
|
PathBufWrp::get_pathbuf(req.match_info().path())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,10 +2,8 @@
|
|||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use futures::Stream;
|
use futures::Stream;
|
||||||
|
|
||||||
use actix_web::dev::ServiceFromRequest;
|
|
||||||
use actix_web::error::{Error, PayloadError};
|
use actix_web::error::{Error, PayloadError};
|
||||||
use actix_web::FromRequest;
|
use actix_web::{dev::Payload, FromRequest, HttpRequest};
|
||||||
use actix_web::HttpMessage;
|
|
||||||
|
|
||||||
use crate::server::Multipart;
|
use crate::server::Multipart;
|
||||||
|
|
||||||
@ -50,8 +48,7 @@ where
|
|||||||
type Future = Result<Multipart, Error>;
|
type Future = Result<Multipart, Error>;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future {
|
fn from_request(req: &HttpRequest, payload: &mut Payload<P>) -> Self::Future {
|
||||||
let pl = req.take_payload();
|
Ok(Multipart::new(req.headers(), payload.take()))
|
||||||
Ok(Multipart::new(req.headers(), pl))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,8 +45,8 @@
|
|||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use actix_web::dev::{ServiceFromRequest, ServiceRequest, ServiceResponse};
|
use actix_web::dev::{Extensions, Payload, ServiceRequest, ServiceResponse};
|
||||||
use actix_web::{Error, FromRequest, HttpMessage};
|
use actix_web::{Error, FromRequest, HttpMessage, HttpRequest};
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use serde::de::DeserializeOwned;
|
use serde::de::DeserializeOwned;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
@ -123,7 +123,7 @@ impl Session {
|
|||||||
data: impl Iterator<Item = (String, String)>,
|
data: impl Iterator<Item = (String, String)>,
|
||||||
req: &mut ServiceRequest<P>,
|
req: &mut ServiceRequest<P>,
|
||||||
) {
|
) {
|
||||||
let session = Session::get_session(req);
|
let session = Session::get_session(&mut *req.extensions_mut());
|
||||||
let mut inner = session.0.borrow_mut();
|
let mut inner = session.0.borrow_mut();
|
||||||
inner.state.extend(data);
|
inner.state.extend(data);
|
||||||
}
|
}
|
||||||
@ -144,12 +144,12 @@ impl Session {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_session<R: HttpMessage>(req: R) -> Session {
|
fn get_session(extensions: &mut Extensions) -> Session {
|
||||||
if let Some(s_impl) = req.extensions().get::<Rc<RefCell<SessionInner>>>() {
|
if let Some(s_impl) = extensions.get::<Rc<RefCell<SessionInner>>>() {
|
||||||
return Session(Rc::clone(&s_impl));
|
return Session(Rc::clone(&s_impl));
|
||||||
}
|
}
|
||||||
let inner = Rc::new(RefCell::new(SessionInner::default()));
|
let inner = Rc::new(RefCell::new(SessionInner::default()));
|
||||||
req.extensions_mut().insert(inner.clone());
|
extensions.insert(inner.clone());
|
||||||
Session(inner)
|
Session(inner)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -177,8 +177,8 @@ impl<P> FromRequest<P> for Session {
|
|||||||
type Future = Result<Session, Error>;
|
type Future = Result<Session, Error>;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future {
|
fn from_request(req: &HttpRequest, _: &mut Payload<P>) -> Self::Future {
|
||||||
Ok(Session::get_session(req))
|
Ok(Session::get_session(&mut *req.extensions_mut()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -196,7 +196,7 @@ mod tests {
|
|||||||
vec![("key".to_string(), "\"value\"".to_string())].into_iter(),
|
vec![("key".to_string(), "\"value\"".to_string())].into_iter(),
|
||||||
&mut req,
|
&mut req,
|
||||||
);
|
);
|
||||||
let session = Session::get_session(&mut req);
|
let session = Session::get_session(&mut *req.extensions_mut());
|
||||||
let res = session.get::<String>("key").unwrap();
|
let res = session.get::<String>("key").unwrap();
|
||||||
assert_eq!(res, Some("value".to_string()));
|
assert_eq!(res, Some("value".to_string()));
|
||||||
|
|
||||||
|
@ -5,8 +5,9 @@ use actix_http::error::{Error, ErrorInternalServerError};
|
|||||||
use actix_http::Extensions;
|
use actix_http::Extensions;
|
||||||
use futures::{Async, Future, IntoFuture, Poll};
|
use futures::{Async, Future, IntoFuture, Poll};
|
||||||
|
|
||||||
|
use crate::dev::Payload;
|
||||||
use crate::extract::FromRequest;
|
use crate::extract::FromRequest;
|
||||||
use crate::service::ServiceFromRequest;
|
use crate::request::HttpRequest;
|
||||||
|
|
||||||
/// Application data factory
|
/// Application data factory
|
||||||
pub(crate) trait DataFactory {
|
pub(crate) trait DataFactory {
|
||||||
@ -91,8 +92,8 @@ impl<T: 'static, P> FromRequest<P> for Data<T> {
|
|||||||
type Future = Result<Self, Error>;
|
type Future = Result<Self, Error>;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future {
|
fn from_request(req: &HttpRequest, _: &mut Payload<P>) -> Self::Future {
|
||||||
if let Some(st) = req.request().config().extensions().get::<Data<T>>() {
|
if let Some(st) = req.app_config().extensions().get::<Data<T>>() {
|
||||||
Ok(st.clone())
|
Ok(st.clone())
|
||||||
} else {
|
} else {
|
||||||
Err(ErrorInternalServerError(
|
Err(ErrorInternalServerError(
|
||||||
@ -230,7 +231,7 @@ impl<T: 'static, P> FromRequest<P> for RouteData<T> {
|
|||||||
type Future = Result<Self, Error>;
|
type Future = Result<Self, Error>;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future {
|
fn from_request(req: &HttpRequest, _: &mut Payload<P>) -> Self::Future {
|
||||||
if let Some(st) = req.route_data::<T>() {
|
if let Some(st) = req.route_data::<T>() {
|
||||||
Ok(st.clone())
|
Ok(st.clone())
|
||||||
} else {
|
} else {
|
||||||
|
@ -4,7 +4,8 @@ use actix_http::error::Error;
|
|||||||
use futures::future::ok;
|
use futures::future::ok;
|
||||||
use futures::{future, Async, Future, IntoFuture, Poll};
|
use futures::{future, Async, Future, IntoFuture, Poll};
|
||||||
|
|
||||||
use crate::service::ServiceFromRequest;
|
use crate::dev::Payload;
|
||||||
|
use crate::request::HttpRequest;
|
||||||
|
|
||||||
/// Trait implemented by types that can be extracted from request.
|
/// Trait implemented by types that can be extracted from request.
|
||||||
///
|
///
|
||||||
@ -17,7 +18,14 @@ pub trait FromRequest<P>: Sized {
|
|||||||
type Future: IntoFuture<Item = Self, Error = Self::Error>;
|
type Future: IntoFuture<Item = Self, Error = Self::Error>;
|
||||||
|
|
||||||
/// Convert request to a Self
|
/// Convert request to a Self
|
||||||
fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future;
|
fn from_request(req: &HttpRequest, payload: &mut Payload<P>) -> Self::Future;
|
||||||
|
|
||||||
|
/// Convert request to a Self
|
||||||
|
///
|
||||||
|
/// This method uses `Payload::None` as payload stream.
|
||||||
|
fn extract(req: &HttpRequest) -> Self::Future {
|
||||||
|
Self::from_request(req, &mut Payload::None)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Optionally extract a field from the request
|
/// Optionally extract a field from the request
|
||||||
@ -28,7 +36,7 @@ pub trait FromRequest<P>: Sized {
|
|||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// # #[macro_use] extern crate serde_derive;
|
/// # #[macro_use] extern crate serde_derive;
|
||||||
/// use actix_web::{web, dev, App, Error, FromRequest};
|
/// use actix_web::{web, dev, App, Error, HttpRequest, FromRequest};
|
||||||
/// use actix_web::error::ErrorBadRequest;
|
/// use actix_web::error::ErrorBadRequest;
|
||||||
/// use rand;
|
/// use rand;
|
||||||
///
|
///
|
||||||
@ -41,7 +49,7 @@ pub trait FromRequest<P>: Sized {
|
|||||||
/// type Error = Error;
|
/// type Error = Error;
|
||||||
/// type Future = Result<Self, Self::Error>;
|
/// type Future = Result<Self, Self::Error>;
|
||||||
///
|
///
|
||||||
/// fn from_request(req: &mut dev::ServiceFromRequest<P>) -> Self::Future {
|
/// fn from_request(req: &HttpRequest, payload: &mut dev::Payload<P>) -> Self::Future {
|
||||||
/// if rand::random() {
|
/// if rand::random() {
|
||||||
/// Ok(Thing { name: "thingy".into() })
|
/// Ok(Thing { name: "thingy".into() })
|
||||||
/// } else {
|
/// } else {
|
||||||
@ -76,14 +84,18 @@ where
|
|||||||
type Future = Box<Future<Item = Option<T>, Error = Error>>;
|
type Future = Box<Future<Item = Option<T>, Error = Error>>;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future {
|
fn from_request(req: &HttpRequest, payload: &mut Payload<P>) -> Self::Future {
|
||||||
Box::new(T::from_request(req).into_future().then(|r| match r {
|
Box::new(
|
||||||
|
T::from_request(req, payload)
|
||||||
|
.into_future()
|
||||||
|
.then(|r| match r {
|
||||||
Ok(v) => future::ok(Some(v)),
|
Ok(v) => future::ok(Some(v)),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::debug!("Error for Option<T> extractor: {}", e.into());
|
log::debug!("Error for Option<T> extractor: {}", e.into());
|
||||||
future::ok(None)
|
future::ok(None)
|
||||||
}
|
}
|
||||||
}))
|
}),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,7 +107,7 @@ where
|
|||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// # #[macro_use] extern crate serde_derive;
|
/// # #[macro_use] extern crate serde_derive;
|
||||||
/// use actix_web::{web, dev, App, Result, Error, FromRequest};
|
/// use actix_web::{web, dev, App, Result, Error, HttpRequest, FromRequest};
|
||||||
/// use actix_web::error::ErrorBadRequest;
|
/// use actix_web::error::ErrorBadRequest;
|
||||||
/// use rand;
|
/// use rand;
|
||||||
///
|
///
|
||||||
@ -108,7 +120,7 @@ where
|
|||||||
/// type Error = Error;
|
/// type Error = Error;
|
||||||
/// type Future = Result<Thing, Error>;
|
/// type Future = Result<Thing, Error>;
|
||||||
///
|
///
|
||||||
/// fn from_request(req: &mut dev::ServiceFromRequest<P>) -> Self::Future {
|
/// fn from_request(req: &HttpRequest, payload: &mut dev::Payload<P>) -> Self::Future {
|
||||||
/// if rand::random() {
|
/// if rand::random() {
|
||||||
/// Ok(Thing { name: "thingy".into() })
|
/// Ok(Thing { name: "thingy".into() })
|
||||||
/// } else {
|
/// } else {
|
||||||
@ -141,11 +153,15 @@ where
|
|||||||
type Future = Box<Future<Item = Result<T, T::Error>, Error = Error>>;
|
type Future = Box<Future<Item = Result<T, T::Error>, Error = Error>>;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future {
|
fn from_request(req: &HttpRequest, payload: &mut Payload<P>) -> Self::Future {
|
||||||
Box::new(T::from_request(req).into_future().then(|res| match res {
|
Box::new(
|
||||||
|
T::from_request(req, payload)
|
||||||
|
.into_future()
|
||||||
|
.then(|res| match res {
|
||||||
Ok(v) => ok(Ok(v)),
|
Ok(v) => ok(Ok(v)),
|
||||||
Err(e) => ok(Err(e)),
|
Err(e) => ok(Err(e)),
|
||||||
}))
|
}),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,7 +170,7 @@ impl<P> FromRequest<P> for () {
|
|||||||
type Error = Error;
|
type Error = Error;
|
||||||
type Future = Result<(), Error>;
|
type Future = Result<(), Error>;
|
||||||
|
|
||||||
fn from_request(_req: &mut ServiceFromRequest<P>) -> Self::Future {
|
fn from_request(_: &HttpRequest, _: &mut Payload<P>) -> Self::Future {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -168,10 +184,10 @@ 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),+>;
|
||||||
|
|
||||||
fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future {
|
fn from_request(req: &HttpRequest, payload: &mut Payload<P>) -> Self::Future {
|
||||||
$fut_type {
|
$fut_type {
|
||||||
items: <($(Option<$T>,)+)>::default(),
|
items: <($(Option<$T>,)+)>::default(),
|
||||||
futs: ($($T::from_request(req).into_future(),)+),
|
futs: ($($T::from_request(req, payload).into_future(),)+),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -247,25 +263,25 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_option() {
|
fn test_option() {
|
||||||
let mut req = TestRequest::with_header(
|
let (req, mut pl) = TestRequest::with_header(
|
||||||
header::CONTENT_TYPE,
|
header::CONTENT_TYPE,
|
||||||
"application/x-www-form-urlencoded",
|
"application/x-www-form-urlencoded",
|
||||||
)
|
)
|
||||||
.route_data(FormConfig::default().limit(4096))
|
.route_data(FormConfig::default().limit(4096))
|
||||||
.to_from();
|
.to_http_parts();
|
||||||
|
|
||||||
let r = block_on(Option::<Form<Info>>::from_request(&mut req)).unwrap();
|
let r = block_on(Option::<Form<Info>>::from_request(&req, &mut pl)).unwrap();
|
||||||
assert_eq!(r, None);
|
assert_eq!(r, None);
|
||||||
|
|
||||||
let mut req = TestRequest::with_header(
|
let (req, mut pl) = TestRequest::with_header(
|
||||||
header::CONTENT_TYPE,
|
header::CONTENT_TYPE,
|
||||||
"application/x-www-form-urlencoded",
|
"application/x-www-form-urlencoded",
|
||||||
)
|
)
|
||||||
.header(header::CONTENT_LENGTH, "9")
|
.header(header::CONTENT_LENGTH, "9")
|
||||||
.set_payload(Bytes::from_static(b"hello=world"))
|
.set_payload(Bytes::from_static(b"hello=world"))
|
||||||
.to_from();
|
.to_http_parts();
|
||||||
|
|
||||||
let r = block_on(Option::<Form<Info>>::from_request(&mut req)).unwrap();
|
let r = block_on(Option::<Form<Info>>::from_request(&req, &mut pl)).unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
r,
|
r,
|
||||||
Some(Form(Info {
|
Some(Form(Info {
|
||||||
@ -273,29 +289,29 @@ mod tests {
|
|||||||
}))
|
}))
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut req = TestRequest::with_header(
|
let (req, mut pl) = TestRequest::with_header(
|
||||||
header::CONTENT_TYPE,
|
header::CONTENT_TYPE,
|
||||||
"application/x-www-form-urlencoded",
|
"application/x-www-form-urlencoded",
|
||||||
)
|
)
|
||||||
.header(header::CONTENT_LENGTH, "9")
|
.header(header::CONTENT_LENGTH, "9")
|
||||||
.set_payload(Bytes::from_static(b"bye=world"))
|
.set_payload(Bytes::from_static(b"bye=world"))
|
||||||
.to_from();
|
.to_http_parts();
|
||||||
|
|
||||||
let r = block_on(Option::<Form<Info>>::from_request(&mut req)).unwrap();
|
let r = block_on(Option::<Form<Info>>::from_request(&req, &mut pl)).unwrap();
|
||||||
assert_eq!(r, None);
|
assert_eq!(r, None);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_result() {
|
fn test_result() {
|
||||||
let mut req = TestRequest::with_header(
|
let (req, mut pl) = TestRequest::with_header(
|
||||||
header::CONTENT_TYPE,
|
header::CONTENT_TYPE,
|
||||||
"application/x-www-form-urlencoded",
|
"application/x-www-form-urlencoded",
|
||||||
)
|
)
|
||||||
.header(header::CONTENT_LENGTH, "11")
|
.header(header::CONTENT_LENGTH, "11")
|
||||||
.set_payload(Bytes::from_static(b"hello=world"))
|
.set_payload(Bytes::from_static(b"hello=world"))
|
||||||
.to_from();
|
.to_http_parts();
|
||||||
|
|
||||||
let r = block_on(Result::<Form<Info>, Error>::from_request(&mut req))
|
let r = block_on(Result::<Form<Info>, Error>::from_request(&req, &mut pl))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -305,15 +321,16 @@ mod tests {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut req = TestRequest::with_header(
|
let (req, mut pl) = TestRequest::with_header(
|
||||||
header::CONTENT_TYPE,
|
header::CONTENT_TYPE,
|
||||||
"application/x-www-form-urlencoded",
|
"application/x-www-form-urlencoded",
|
||||||
)
|
)
|
||||||
.header(header::CONTENT_LENGTH, "9")
|
.header(header::CONTENT_LENGTH, "9")
|
||||||
.set_payload(Bytes::from_static(b"bye=world"))
|
.set_payload(Bytes::from_static(b"bye=world"))
|
||||||
.to_from();
|
.to_http_parts();
|
||||||
|
|
||||||
let r = block_on(Result::<Form<Info>, Error>::from_request(&mut req)).unwrap();
|
let r =
|
||||||
|
block_on(Result::<Form<Info>, Error>::from_request(&req, &mut pl)).unwrap();
|
||||||
assert!(r.is_err());
|
assert!(r.is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -336,37 +353,38 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_request_extract() {
|
fn test_request_extract() {
|
||||||
let mut req = TestRequest::with_uri("/name/user1/?id=test").to_from();
|
let mut req = TestRequest::with_uri("/name/user1/?id=test").to_srv_request();
|
||||||
|
|
||||||
let resource = ResourceDef::new("/{key}/{value}/");
|
let resource = ResourceDef::new("/{key}/{value}/");
|
||||||
resource.match_path(req.match_info_mut());
|
resource.match_path(req.match_info_mut());
|
||||||
|
|
||||||
let s = Path::<MyStruct>::from_request(&mut req).unwrap();
|
let (req, mut pl) = req.into_parts();
|
||||||
|
let s = Path::<MyStruct>::from_request(&req, &mut pl).unwrap();
|
||||||
assert_eq!(s.key, "name");
|
assert_eq!(s.key, "name");
|
||||||
assert_eq!(s.value, "user1");
|
assert_eq!(s.value, "user1");
|
||||||
|
|
||||||
let s = Path::<(String, String)>::from_request(&mut req).unwrap();
|
let s = Path::<(String, String)>::from_request(&req, &mut pl).unwrap();
|
||||||
assert_eq!(s.0, "name");
|
assert_eq!(s.0, "name");
|
||||||
assert_eq!(s.1, "user1");
|
assert_eq!(s.1, "user1");
|
||||||
|
|
||||||
let s = Query::<Id>::from_request(&mut req).unwrap();
|
let s = Query::<Id>::from_request(&req, &mut pl).unwrap();
|
||||||
assert_eq!(s.id, "test");
|
assert_eq!(s.id, "test");
|
||||||
|
|
||||||
let mut req = TestRequest::with_uri("/name/32/").to_from();
|
let mut req = TestRequest::with_uri("/name/32/").to_srv_request();
|
||||||
let resource = ResourceDef::new("/{key}/{value}/");
|
let resource = ResourceDef::new("/{key}/{value}/");
|
||||||
resource.match_path(req.match_info_mut());
|
resource.match_path(req.match_info_mut());
|
||||||
|
|
||||||
let s = Path::<Test2>::from_request(&mut req).unwrap();
|
let (req, mut pl) = req.into_parts();
|
||||||
|
let s = Path::<Test2>::from_request(&req, &mut pl).unwrap();
|
||||||
assert_eq!(s.as_ref().key, "name");
|
assert_eq!(s.as_ref().key, "name");
|
||||||
assert_eq!(s.value, 32);
|
assert_eq!(s.value, 32);
|
||||||
|
|
||||||
let s = Path::<(String, u8)>::from_request(&mut req).unwrap();
|
let s = Path::<(String, u8)>::from_request(&req, &mut pl).unwrap();
|
||||||
assert_eq!(s.0, "name");
|
assert_eq!(s.0, "name");
|
||||||
assert_eq!(s.1, 32);
|
assert_eq!(s.1, 32);
|
||||||
|
|
||||||
let res = Path::<Vec<String>>::from_request(&mut req).unwrap();
|
let res = Path::<Vec<String>>::from_request(&req, &mut pl).unwrap();
|
||||||
assert_eq!(res[0], "name".to_owned());
|
assert_eq!(res[0], "name".to_owned());
|
||||||
assert_eq!(res[1], "32".to_owned());
|
assert_eq!(res[1], "32".to_owned());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ use std::cell::RefCell;
|
|||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use actix_http::{Error, Extensions, Response};
|
use actix_http::{Error, Extensions, Payload, 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};
|
||||||
@ -10,7 +10,7 @@ use futures::{try_ready, Async, Future, IntoFuture, Poll};
|
|||||||
use crate::extract::FromRequest;
|
use crate::extract::FromRequest;
|
||||||
use crate::request::HttpRequest;
|
use crate::request::HttpRequest;
|
||||||
use crate::responder::Responder;
|
use crate::responder::Responder;
|
||||||
use crate::service::{ServiceFromRequest, ServiceRequest, ServiceResponse};
|
use crate::service::{ServiceRequest, ServiceResponse};
|
||||||
|
|
||||||
/// Handler converter factory
|
/// Handler converter factory
|
||||||
pub trait Factory<T, R>: Clone
|
pub trait Factory<T, R>: Clone
|
||||||
@ -293,7 +293,7 @@ impl<P, T: FromRequest<P>> Extract<P, T> {
|
|||||||
impl<P, T: FromRequest<P>> NewService for Extract<P, T> {
|
impl<P, T: FromRequest<P>> NewService for Extract<P, T> {
|
||||||
type Request = ServiceRequest<P>;
|
type Request = ServiceRequest<P>;
|
||||||
type Response = (T, HttpRequest);
|
type Response = (T, HttpRequest);
|
||||||
type Error = (Error, ServiceFromRequest<P>);
|
type Error = (Error, ServiceRequest<P>);
|
||||||
type InitError = ();
|
type InitError = ();
|
||||||
type Service = ExtractService<P, T>;
|
type Service = ExtractService<P, T>;
|
||||||
type Future = FutureResult<Self::Service, ()>;
|
type Future = FutureResult<Self::Service, ()>;
|
||||||
@ -314,7 +314,7 @@ pub struct ExtractService<P, T: FromRequest<P>> {
|
|||||||
impl<P, T: FromRequest<P>> Service for ExtractService<P, T> {
|
impl<P, T: FromRequest<P>> Service for ExtractService<P, T> {
|
||||||
type Request = ServiceRequest<P>;
|
type Request = ServiceRequest<P>;
|
||||||
type Response = (T, HttpRequest);
|
type Response = (T, HttpRequest);
|
||||||
type Error = (Error, ServiceFromRequest<P>);
|
type Error = (Error, ServiceRequest<P>);
|
||||||
type Future = ExtractResponse<P, T>;
|
type Future = ExtractResponse<P, T>;
|
||||||
|
|
||||||
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
|
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
|
||||||
@ -322,33 +322,34 @@ 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 = ServiceFromRequest::new(req, self.config.clone());
|
let (mut req, mut payload) = req.into_parts();
|
||||||
|
req.set_route_data(self.config.clone());
|
||||||
|
let fut = T::from_request(&req, &mut payload).into_future();
|
||||||
|
|
||||||
ExtractResponse {
|
ExtractResponse {
|
||||||
fut: T::from_request(&mut req).into_future(),
|
fut,
|
||||||
req: Some(req),
|
req: Some((req, payload)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ExtractResponse<P, T: FromRequest<P>> {
|
pub struct ExtractResponse<P, T: FromRequest<P>> {
|
||||||
req: Option<ServiceFromRequest<P>>,
|
req: Option<(HttpRequest, Payload<P>)>,
|
||||||
fut: <T::Future as IntoFuture>::Future,
|
fut: <T::Future as IntoFuture>::Future,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P, T: FromRequest<P>> Future for ExtractResponse<P, T> {
|
impl<P, T: FromRequest<P>> Future for ExtractResponse<P, T> {
|
||||||
type Item = (T, HttpRequest);
|
type Item = (T, HttpRequest);
|
||||||
type Error = (Error, ServiceFromRequest<P>);
|
type Error = (Error, ServiceRequest<P>);
|
||||||
|
|
||||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||||
let item = try_ready!(self
|
let item = try_ready!(self.fut.poll().map_err(|e| {
|
||||||
.fut
|
let (req, payload) = self.req.take().unwrap();
|
||||||
.poll()
|
let req = ServiceRequest::from_parts(req, payload);
|
||||||
.map_err(|e| (e.into(), self.req.take().unwrap())));
|
(e.into(), req)
|
||||||
|
}));
|
||||||
|
|
||||||
let req = self.req.take().unwrap();
|
Ok(Async::Ready((item, self.req.take().unwrap().0)))
|
||||||
let req = req.into_request();
|
|
||||||
|
|
||||||
Ok(Async::Ready((item, req)))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,9 +138,7 @@ pub mod dev {
|
|||||||
pub use crate::config::{AppConfig, ServiceConfig};
|
pub use crate::config::{AppConfig, ServiceConfig};
|
||||||
pub use crate::info::ConnectionInfo;
|
pub use crate::info::ConnectionInfo;
|
||||||
pub use crate::rmap::ResourceMap;
|
pub use crate::rmap::ResourceMap;
|
||||||
pub use crate::service::{
|
pub use crate::service::{HttpServiceFactory, ServiceRequest, ServiceResponse};
|
||||||
HttpServiceFactory, ServiceFromRequest, ServiceRequest, ServiceResponse,
|
|
||||||
};
|
|
||||||
pub use crate::types::form::UrlEncoded;
|
pub use crate::types::form::UrlEncoded;
|
||||||
pub use crate::types::json::JsonBody;
|
pub use crate::types::json::JsonBody;
|
||||||
pub use crate::types::readlines::Readlines;
|
pub use crate::types::readlines::Readlines;
|
||||||
|
@ -58,10 +58,8 @@ use time::Duration;
|
|||||||
use crate::cookie::{Cookie, CookieJar, Key, SameSite};
|
use crate::cookie::{Cookie, CookieJar, Key, SameSite};
|
||||||
use crate::error::{Error, Result};
|
use crate::error::{Error, Result};
|
||||||
use crate::http::header::{self, HeaderValue};
|
use crate::http::header::{self, HeaderValue};
|
||||||
use crate::request::HttpRequest;
|
use crate::service::{ServiceRequest, ServiceResponse};
|
||||||
use crate::service::{ServiceFromRequest, ServiceRequest, ServiceResponse};
|
use crate::{dev::Payload, FromRequest, HttpMessage, HttpRequest};
|
||||||
use crate::FromRequest;
|
|
||||||
use crate::HttpMessage;
|
|
||||||
|
|
||||||
/// The extractor type to obtain your identity from a request.
|
/// The extractor type to obtain your identity from a request.
|
||||||
///
|
///
|
||||||
@ -147,8 +145,8 @@ impl<P> FromRequest<P> for Identity {
|
|||||||
type Future = Result<Identity, Error>;
|
type Future = Result<Identity, Error>;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future {
|
fn from_request(req: &HttpRequest, _: &mut Payload<P>) -> Self::Future {
|
||||||
Ok(Identity(req.request().clone()))
|
Ok(Identity(req.clone()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,12 +7,11 @@ use actix_http::{Error, Extensions, HttpMessage, Message, Payload, RequestHead};
|
|||||||
use actix_router::{Path, Url};
|
use actix_router::{Path, Url};
|
||||||
|
|
||||||
use crate::config::AppConfig;
|
use crate::config::AppConfig;
|
||||||
use crate::data::Data;
|
use crate::data::{Data, RouteData};
|
||||||
use crate::error::UrlGenerationError;
|
use crate::error::UrlGenerationError;
|
||||||
use crate::extract::FromRequest;
|
use crate::extract::FromRequest;
|
||||||
use crate::info::ConnectionInfo;
|
use crate::info::ConnectionInfo;
|
||||||
use crate::rmap::ResourceMap;
|
use crate::rmap::ResourceMap;
|
||||||
use crate::service::ServiceFromRequest;
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
/// An HTTP Request
|
/// An HTTP Request
|
||||||
@ -21,6 +20,7 @@ pub struct HttpRequest {
|
|||||||
pub(crate) path: Path<Url>,
|
pub(crate) path: Path<Url>,
|
||||||
rmap: Rc<ResourceMap>,
|
rmap: Rc<ResourceMap>,
|
||||||
config: AppConfig,
|
config: AppConfig,
|
||||||
|
route_data: Option<Rc<Extensions>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HttpRequest {
|
impl HttpRequest {
|
||||||
@ -36,6 +36,7 @@ impl HttpRequest {
|
|||||||
path,
|
path,
|
||||||
rmap,
|
rmap,
|
||||||
config,
|
config,
|
||||||
|
route_data: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -100,22 +101,6 @@ impl HttpRequest {
|
|||||||
&self.path
|
&self.path
|
||||||
}
|
}
|
||||||
|
|
||||||
/// App config
|
|
||||||
#[inline]
|
|
||||||
pub fn config(&self) -> &AppConfig {
|
|
||||||
&self.config
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get an application data stored with `App::data()` method during
|
|
||||||
/// application configuration.
|
|
||||||
pub fn app_data<T: 'static>(&self) -> Option<Data<T>> {
|
|
||||||
if let Some(st) = self.config.extensions().get::<Data<T>>() {
|
|
||||||
Some(st.clone())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Request extensions
|
/// Request extensions
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn extensions(&self) -> Ref<Extensions> {
|
pub fn extensions(&self) -> Ref<Extensions> {
|
||||||
@ -171,7 +156,37 @@ impl HttpRequest {
|
|||||||
/// Get *ConnectionInfo* for the current request.
|
/// Get *ConnectionInfo* for the current request.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn connection_info(&self) -> Ref<ConnectionInfo> {
|
pub fn connection_info(&self) -> Ref<ConnectionInfo> {
|
||||||
ConnectionInfo::get(self.head(), &*self.config())
|
ConnectionInfo::get(self.head(), &*self.app_config())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// App config
|
||||||
|
#[inline]
|
||||||
|
pub fn app_config(&self) -> &AppConfig {
|
||||||
|
&self.config
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get an application data stored with `App::data()` method during
|
||||||
|
/// application configuration.
|
||||||
|
pub fn app_data<T: 'static>(&self) -> Option<Data<T>> {
|
||||||
|
if let Some(st) = self.config.extensions().get::<Data<T>>() {
|
||||||
|
Some(st.clone())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Load route data. Route data could be set during
|
||||||
|
/// route configuration with `Route::data()` method.
|
||||||
|
pub fn route_data<T: 'static>(&self) -> Option<&RouteData<T>> {
|
||||||
|
if let Some(ref ext) = self.route_data {
|
||||||
|
ext.get::<RouteData<T>>()
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn set_route_data(&mut self, data: Option<Rc<Extensions>>) {
|
||||||
|
self.route_data = data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -227,8 +242,8 @@ impl<P> FromRequest<P> for HttpRequest {
|
|||||||
type Future = Result<Self, Error>;
|
type Future = Result<Self, Error>;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future {
|
fn from_request(req: &HttpRequest, _: &mut Payload<P>) -> Self::Future {
|
||||||
Ok(req.request().clone())
|
Ok(req.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
10
src/route.rs
10
src/route.rs
@ -11,7 +11,7 @@ use crate::extract::FromRequest;
|
|||||||
use crate::guard::{self, Guard};
|
use crate::guard::{self, Guard};
|
||||||
use crate::handler::{AsyncFactory, AsyncHandler, Extract, Factory, Handler};
|
use crate::handler::{AsyncFactory, AsyncHandler, Extract, Factory, Handler};
|
||||||
use crate::responder::Responder;
|
use crate::responder::Responder;
|
||||||
use crate::service::{ServiceFromRequest, ServiceRequest, ServiceResponse};
|
use crate::service::{ServiceRequest, ServiceResponse};
|
||||||
use crate::HttpResponse;
|
use crate::HttpResponse;
|
||||||
|
|
||||||
type BoxedRouteService<Req, Res> = Box<
|
type BoxedRouteService<Req, Res> = Box<
|
||||||
@ -317,7 +317,7 @@ impl<P: 'static> Route<P> {
|
|||||||
|
|
||||||
struct RouteNewService<P, T>
|
struct RouteNewService<P, T>
|
||||||
where
|
where
|
||||||
T: NewService<Request = ServiceRequest<P>, Error = (Error, ServiceFromRequest<P>)>,
|
T: NewService<Request = ServiceRequest<P>, Error = (Error, ServiceRequest<P>)>,
|
||||||
{
|
{
|
||||||
service: T,
|
service: T,
|
||||||
_t: PhantomData<P>,
|
_t: PhantomData<P>,
|
||||||
@ -328,7 +328,7 @@ where
|
|||||||
T: NewService<
|
T: NewService<
|
||||||
Request = ServiceRequest<P>,
|
Request = ServiceRequest<P>,
|
||||||
Response = ServiceResponse,
|
Response = ServiceResponse,
|
||||||
Error = (Error, ServiceFromRequest<P>),
|
Error = (Error, ServiceRequest<P>),
|
||||||
>,
|
>,
|
||||||
T::Future: 'static,
|
T::Future: 'static,
|
||||||
T::Service: 'static,
|
T::Service: 'static,
|
||||||
@ -347,7 +347,7 @@ where
|
|||||||
T: NewService<
|
T: NewService<
|
||||||
Request = ServiceRequest<P>,
|
Request = ServiceRequest<P>,
|
||||||
Response = ServiceResponse,
|
Response = ServiceResponse,
|
||||||
Error = (Error, ServiceFromRequest<P>),
|
Error = (Error, ServiceRequest<P>),
|
||||||
>,
|
>,
|
||||||
T::Future: 'static,
|
T::Future: 'static,
|
||||||
T::Service: 'static,
|
T::Service: 'static,
|
||||||
@ -388,7 +388,7 @@ where
|
|||||||
T: Service<
|
T: Service<
|
||||||
Request = ServiceRequest<P>,
|
Request = ServiceRequest<P>,
|
||||||
Response = ServiceResponse,
|
Response = ServiceResponse,
|
||||||
Error = (Error, ServiceFromRequest<P>),
|
Error = (Error, ServiceRequest<P>),
|
||||||
>,
|
>,
|
||||||
{
|
{
|
||||||
type Request = ServiceRequest<P>;
|
type Request = ServiceRequest<P>;
|
||||||
|
@ -13,7 +13,7 @@ use actix_router::{Path, Resource, Url};
|
|||||||
use futures::future::{ok, FutureResult, IntoFuture};
|
use futures::future::{ok, FutureResult, IntoFuture};
|
||||||
|
|
||||||
use crate::config::{AppConfig, ServiceConfig};
|
use crate::config::{AppConfig, ServiceConfig};
|
||||||
use crate::data::{Data, RouteData};
|
use crate::data::Data;
|
||||||
use crate::request::HttpRequest;
|
use crate::request::HttpRequest;
|
||||||
use crate::rmap::ResourceMap;
|
use crate::rmap::ResourceMap;
|
||||||
|
|
||||||
@ -171,13 +171,13 @@ impl<P> ServiceRequest<P> {
|
|||||||
/// Service configuration
|
/// Service configuration
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn app_config(&self) -> &AppConfig {
|
pub fn app_config(&self) -> &AppConfig {
|
||||||
self.req.config()
|
self.req.app_config()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get an application data stored with `App::data()` method during
|
/// Get an application data stored with `App::data()` method during
|
||||||
/// application configuration.
|
/// application configuration.
|
||||||
pub fn app_data<T: 'static>(&self) -> Option<Data<T>> {
|
pub fn app_data<T: 'static>(&self) -> Option<Data<T>> {
|
||||||
if let Some(st) = self.req.config().extensions().get::<Data<T>>() {
|
if let Some(st) = self.req.app_config().extensions().get::<Data<T>>() {
|
||||||
Some(st.clone())
|
Some(st.clone())
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
@ -241,92 +241,6 @@ impl<P> fmt::Debug for ServiceRequest<P> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ServiceFromRequest<P> {
|
|
||||||
req: HttpRequest,
|
|
||||||
payload: Payload<P>,
|
|
||||||
data: Option<Rc<Extensions>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<P> ServiceFromRequest<P> {
|
|
||||||
pub(crate) fn new(req: ServiceRequest<P>, data: Option<Rc<Extensions>>) -> Self {
|
|
||||||
Self {
|
|
||||||
req: req.req,
|
|
||||||
payload: req.payload,
|
|
||||||
data,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
/// Get reference to inner HttpRequest
|
|
||||||
pub fn request(&self) -> &HttpRequest {
|
|
||||||
&self.req
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
/// Convert this request into a HttpRequest
|
|
||||||
pub fn into_request(self) -> HttpRequest {
|
|
||||||
self.req
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
/// Get match information for this request
|
|
||||||
pub fn match_info_mut(&mut self) -> &mut Path<Url> {
|
|
||||||
&mut self.req.path
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create service response for error
|
|
||||||
#[inline]
|
|
||||||
pub fn error_response<E: Into<Error>>(self, err: E) -> ServiceResponse {
|
|
||||||
ServiceResponse::new(self.req, err.into().into())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get an application data stored with `App::data()` method during
|
|
||||||
/// application configuration.
|
|
||||||
pub fn app_data<T: 'static>(&self) -> Option<Data<T>> {
|
|
||||||
if let Some(st) = self.req.config().extensions().get::<Data<T>>() {
|
|
||||||
Some(st.clone())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Load route data. Route data could be set during
|
|
||||||
/// route configuration with `Route::data()` method.
|
|
||||||
pub fn route_data<T: 'static>(&self) -> Option<&RouteData<T>> {
|
|
||||||
if let Some(ref ext) = self.data {
|
|
||||||
ext.get::<RouteData<T>>()
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<P> HttpMessage for ServiceFromRequest<P> {
|
|
||||||
type Stream = P;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn headers(&self) -> &HeaderMap {
|
|
||||||
self.req.headers()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Request extensions
|
|
||||||
#[inline]
|
|
||||||
fn extensions(&self) -> Ref<Extensions> {
|
|
||||||
self.req.head.extensions()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Mutable reference to a the request's extensions
|
|
||||||
#[inline]
|
|
||||||
fn extensions_mut(&self) -> RefMut<Extensions> {
|
|
||||||
self.req.head.extensions_mut()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn take_payload(&mut self) -> Payload<Self::Stream> {
|
|
||||||
std::mem::replace(&mut self.payload, Payload::None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ServiceResponse<B = Body> {
|
pub struct ServiceResponse<B = Body> {
|
||||||
request: HttpRequest,
|
request: HttpRequest,
|
||||||
response: Response<B>,
|
response: Response<B>,
|
||||||
|
33
src/test.rs
33
src/test.rs
@ -16,9 +16,9 @@ use futures::future::{lazy, Future};
|
|||||||
|
|
||||||
use crate::config::{AppConfig, AppConfigInner};
|
use crate::config::{AppConfig, AppConfigInner};
|
||||||
use crate::data::RouteData;
|
use crate::data::RouteData;
|
||||||
use crate::dev::Body;
|
use crate::dev::{Body, Payload};
|
||||||
use crate::rmap::ResourceMap;
|
use crate::rmap::ResourceMap;
|
||||||
use crate::service::{ServiceFromRequest, ServiceRequest, ServiceResponse};
|
use crate::service::{ServiceRequest, ServiceResponse};
|
||||||
use crate::{Error, HttpRequest, HttpResponse};
|
use crate::{Error, HttpRequest, HttpResponse};
|
||||||
|
|
||||||
thread_local! {
|
thread_local! {
|
||||||
@ -319,6 +319,11 @@ impl TestRequest {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Complete request creation and generate `Request` instance
|
||||||
|
pub fn to_request(mut self) -> Request<PayloadStream> {
|
||||||
|
self.req.finish()
|
||||||
|
}
|
||||||
|
|
||||||
/// Complete request creation and generate `ServiceRequest` instance
|
/// Complete request creation and generate `ServiceRequest` instance
|
||||||
pub fn to_srv_request(mut self) -> ServiceRequest<PayloadStream> {
|
pub fn to_srv_request(mut self) -> ServiceRequest<PayloadStream> {
|
||||||
let req = self.req.finish();
|
let req = self.req.finish();
|
||||||
@ -336,36 +341,36 @@ impl TestRequest {
|
|||||||
self.to_srv_request().into_response(res)
|
self.to_srv_request().into_response(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Complete request creation and generate `Request` instance
|
|
||||||
pub fn to_request(mut self) -> Request<PayloadStream> {
|
|
||||||
self.req.finish()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Complete request creation and generate `HttpRequest` instance
|
/// Complete request creation and generate `HttpRequest` instance
|
||||||
pub fn to_http_request(mut self) -> HttpRequest {
|
pub fn to_http_request(mut self) -> HttpRequest {
|
||||||
let req = self.req.finish();
|
let req = self.req.finish();
|
||||||
|
|
||||||
ServiceRequest::new(
|
let mut req = ServiceRequest::new(
|
||||||
Path::new(Url::new(req.uri().clone())),
|
Path::new(Url::new(req.uri().clone())),
|
||||||
req,
|
req,
|
||||||
Rc::new(self.rmap),
|
Rc::new(self.rmap),
|
||||||
AppConfig::new(self.config),
|
AppConfig::new(self.config),
|
||||||
)
|
)
|
||||||
.into_parts()
|
.into_parts()
|
||||||
.0
|
.0;
|
||||||
|
req.set_route_data(Some(Rc::new(self.route_data)));
|
||||||
|
req
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Complete request creation and generate `ServiceFromRequest` instance
|
/// Complete request creation and generate `HttpRequest` and `Payload` instances
|
||||||
pub fn to_from(mut self) -> ServiceFromRequest<PayloadStream> {
|
pub fn to_http_parts(mut self) -> (HttpRequest, Payload) {
|
||||||
let req = self.req.finish();
|
let req = self.req.finish();
|
||||||
|
|
||||||
let req = ServiceRequest::new(
|
let (mut req, pl) = ServiceRequest::new(
|
||||||
Path::new(Url::new(req.uri().clone())),
|
Path::new(Url::new(req.uri().clone())),
|
||||||
req,
|
req,
|
||||||
Rc::new(self.rmap),
|
Rc::new(self.rmap),
|
||||||
AppConfig::new(self.config),
|
AppConfig::new(self.config),
|
||||||
);
|
)
|
||||||
ServiceFromRequest::new(req, Some(Rc::new(self.route_data)))
|
.into_parts();
|
||||||
|
|
||||||
|
req.set_route_data(Some(Rc::new(self.route_data)));
|
||||||
|
(req, pl)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Runs the provided future, blocking the current thread until the future
|
/// Runs the provided future, blocking the current thread until the future
|
||||||
|
@ -16,7 +16,6 @@ use crate::error::UrlencodedError;
|
|||||||
use crate::extract::FromRequest;
|
use crate::extract::FromRequest;
|
||||||
use crate::http::header::CONTENT_LENGTH;
|
use crate::http::header::CONTENT_LENGTH;
|
||||||
use crate::request::HttpRequest;
|
use crate::request::HttpRequest;
|
||||||
use crate::service::ServiceFromRequest;
|
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(PartialEq, Eq, PartialOrd, Ord)]
|
||||||
/// Extract typed information from the request's body.
|
/// Extract typed information from the request's body.
|
||||||
@ -79,15 +78,15 @@ where
|
|||||||
type Future = Box<Future<Item = Self, Error = Error>>;
|
type Future = Box<Future<Item = Self, Error = Error>>;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future {
|
fn from_request(req: &HttpRequest, payload: &mut Payload<P>) -> Self::Future {
|
||||||
let req2 = req.request().clone();
|
let req2 = req.clone();
|
||||||
let (limit, err) = req
|
let (limit, err) = req
|
||||||
.route_data::<FormConfig>()
|
.route_data::<FormConfig>()
|
||||||
.map(|c| (c.limit, c.ehandler.clone()))
|
.map(|c| (c.limit, c.ehandler.clone()))
|
||||||
.unwrap_or((16384, None));
|
.unwrap_or((16384, None));
|
||||||
|
|
||||||
Box::new(
|
Box::new(
|
||||||
UrlEncoded::new(req)
|
UrlEncoded::new(req, payload)
|
||||||
.limit(limit)
|
.limit(limit)
|
||||||
.map_err(move |e| {
|
.map_err(move |e| {
|
||||||
if let Some(err) = err {
|
if let Some(err) = err {
|
||||||
@ -183,8 +182,8 @@ impl Default for FormConfig {
|
|||||||
/// * content type is not `application/x-www-form-urlencoded`
|
/// * content type is not `application/x-www-form-urlencoded`
|
||||||
/// * content-length is greater than 32k
|
/// * content-length is greater than 32k
|
||||||
///
|
///
|
||||||
pub struct UrlEncoded<T: HttpMessage, U> {
|
pub struct UrlEncoded<P, U> {
|
||||||
stream: Payload<T::Stream>,
|
stream: Payload<P>,
|
||||||
limit: usize,
|
limit: usize,
|
||||||
length: Option<usize>,
|
length: Option<usize>,
|
||||||
encoding: EncodingRef,
|
encoding: EncodingRef,
|
||||||
@ -192,13 +191,12 @@ pub struct UrlEncoded<T: HttpMessage, U> {
|
|||||||
fut: Option<Box<Future<Item = U, Error = UrlencodedError>>>,
|
fut: Option<Box<Future<Item = U, Error = UrlencodedError>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, U> UrlEncoded<T, U>
|
impl<P, U> UrlEncoded<P, U>
|
||||||
where
|
where
|
||||||
T: HttpMessage,
|
P: Stream<Item = Bytes, Error = PayloadError>,
|
||||||
T::Stream: Stream<Item = Bytes, Error = PayloadError>,
|
|
||||||
{
|
{
|
||||||
/// Create a new future to URL encode a request
|
/// Create a new future to URL encode a request
|
||||||
pub fn new(req: &mut T) -> UrlEncoded<T, U> {
|
pub fn new(req: &HttpRequest, payload: &mut Payload<P>) -> UrlEncoded<P, U> {
|
||||||
// check content type
|
// check content type
|
||||||
if req.content_type().to_lowercase() != "application/x-www-form-urlencoded" {
|
if req.content_type().to_lowercase() != "application/x-www-form-urlencoded" {
|
||||||
return Self::err(UrlencodedError::ContentType);
|
return Self::err(UrlencodedError::ContentType);
|
||||||
@ -223,7 +221,7 @@ where
|
|||||||
|
|
||||||
UrlEncoded {
|
UrlEncoded {
|
||||||
encoding,
|
encoding,
|
||||||
stream: req.take_payload(),
|
stream: payload.take(),
|
||||||
limit: 32_768,
|
limit: 32_768,
|
||||||
length: len,
|
length: len,
|
||||||
fut: None,
|
fut: None,
|
||||||
@ -249,10 +247,9 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, U> Future for UrlEncoded<T, U>
|
impl<P, U> Future for UrlEncoded<P, U>
|
||||||
where
|
where
|
||||||
T: HttpMessage,
|
P: Stream<Item = Bytes, Error = PayloadError> + 'static,
|
||||||
T::Stream: Stream<Item = Bytes, Error = PayloadError> + 'static,
|
|
||||||
U: DeserializeOwned + 'static,
|
U: DeserializeOwned + 'static,
|
||||||
{
|
{
|
||||||
type Item = U;
|
type Item = U;
|
||||||
@ -320,13 +317,13 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_form() {
|
fn test_form() {
|
||||||
let mut req =
|
let (req, mut pl) =
|
||||||
TestRequest::with_header(CONTENT_TYPE, "application/x-www-form-urlencoded")
|
TestRequest::with_header(CONTENT_TYPE, "application/x-www-form-urlencoded")
|
||||||
.header(CONTENT_LENGTH, "11")
|
.header(CONTENT_LENGTH, "11")
|
||||||
.set_payload(Bytes::from_static(b"hello=world"))
|
.set_payload(Bytes::from_static(b"hello=world"))
|
||||||
.to_from();
|
.to_http_parts();
|
||||||
|
|
||||||
let s = block_on(Form::<Info>::from_request(&mut req)).unwrap();
|
let s = block_on(Form::<Info>::from_request(&req, &mut pl)).unwrap();
|
||||||
assert_eq!(s.hello, "world");
|
assert_eq!(s.hello, "world");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -354,36 +351,36 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_urlencoded_error() {
|
fn test_urlencoded_error() {
|
||||||
let mut req =
|
let (req, mut pl) =
|
||||||
TestRequest::with_header(CONTENT_TYPE, "application/x-www-form-urlencoded")
|
TestRequest::with_header(CONTENT_TYPE, "application/x-www-form-urlencoded")
|
||||||
.header(CONTENT_LENGTH, "xxxx")
|
.header(CONTENT_LENGTH, "xxxx")
|
||||||
.to_request();
|
.to_http_parts();
|
||||||
let info = block_on(UrlEncoded::<_, Info>::new(&mut req));
|
let info = block_on(UrlEncoded::<_, Info>::new(&req, &mut pl));
|
||||||
assert!(eq(info.err().unwrap(), UrlencodedError::UnknownLength));
|
assert!(eq(info.err().unwrap(), UrlencodedError::UnknownLength));
|
||||||
|
|
||||||
let mut req =
|
let (req, mut pl) =
|
||||||
TestRequest::with_header(CONTENT_TYPE, "application/x-www-form-urlencoded")
|
TestRequest::with_header(CONTENT_TYPE, "application/x-www-form-urlencoded")
|
||||||
.header(CONTENT_LENGTH, "1000000")
|
.header(CONTENT_LENGTH, "1000000")
|
||||||
.to_request();
|
.to_http_parts();
|
||||||
let info = block_on(UrlEncoded::<_, Info>::new(&mut req));
|
let info = block_on(UrlEncoded::<_, Info>::new(&req, &mut pl));
|
||||||
assert!(eq(info.err().unwrap(), UrlencodedError::Overflow));
|
assert!(eq(info.err().unwrap(), UrlencodedError::Overflow));
|
||||||
|
|
||||||
let mut req = TestRequest::with_header(CONTENT_TYPE, "text/plain")
|
let (req, mut pl) = TestRequest::with_header(CONTENT_TYPE, "text/plain")
|
||||||
.header(CONTENT_LENGTH, "10")
|
.header(CONTENT_LENGTH, "10")
|
||||||
.to_request();
|
.to_http_parts();
|
||||||
let info = block_on(UrlEncoded::<_, Info>::new(&mut req));
|
let info = block_on(UrlEncoded::<_, Info>::new(&req, &mut pl));
|
||||||
assert!(eq(info.err().unwrap(), UrlencodedError::ContentType));
|
assert!(eq(info.err().unwrap(), UrlencodedError::ContentType));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_urlencoded() {
|
fn test_urlencoded() {
|
||||||
let mut req =
|
let (req, mut pl) =
|
||||||
TestRequest::with_header(CONTENT_TYPE, "application/x-www-form-urlencoded")
|
TestRequest::with_header(CONTENT_TYPE, "application/x-www-form-urlencoded")
|
||||||
.header(CONTENT_LENGTH, "11")
|
.header(CONTENT_LENGTH, "11")
|
||||||
.set_payload(Bytes::from_static(b"hello=world"))
|
.set_payload(Bytes::from_static(b"hello=world"))
|
||||||
.to_request();
|
.to_http_parts();
|
||||||
|
|
||||||
let info = block_on(UrlEncoded::<_, Info>::new(&mut req)).unwrap();
|
let info = block_on(UrlEncoded::<_, Info>::new(&req, &mut pl)).unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
info,
|
info,
|
||||||
Info {
|
Info {
|
||||||
@ -391,15 +388,15 @@ mod tests {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut req = TestRequest::with_header(
|
let (req, mut pl) = TestRequest::with_header(
|
||||||
CONTENT_TYPE,
|
CONTENT_TYPE,
|
||||||
"application/x-www-form-urlencoded; charset=utf-8",
|
"application/x-www-form-urlencoded; charset=utf-8",
|
||||||
)
|
)
|
||||||
.header(CONTENT_LENGTH, "11")
|
.header(CONTENT_LENGTH, "11")
|
||||||
.set_payload(Bytes::from_static(b"hello=world"))
|
.set_payload(Bytes::from_static(b"hello=world"))
|
||||||
.to_request();
|
.to_http_parts();
|
||||||
|
|
||||||
let info = block_on(UrlEncoded::<_, Info>::new(&mut req)).unwrap();
|
let info = block_on(UrlEncoded::<_, Info>::new(&req, &mut pl)).unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
info,
|
info,
|
||||||
Info {
|
Info {
|
||||||
|
@ -16,7 +16,6 @@ use crate::error::{Error, JsonPayloadError, PayloadError};
|
|||||||
use crate::extract::FromRequest;
|
use crate::extract::FromRequest;
|
||||||
use crate::request::HttpRequest;
|
use crate::request::HttpRequest;
|
||||||
use crate::responder::Responder;
|
use crate::responder::Responder;
|
||||||
use crate::service::ServiceFromRequest;
|
|
||||||
|
|
||||||
/// Json helper
|
/// Json helper
|
||||||
///
|
///
|
||||||
@ -173,15 +172,15 @@ where
|
|||||||
type Future = Box<Future<Item = Self, Error = Error>>;
|
type Future = Box<Future<Item = Self, Error = Error>>;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future {
|
fn from_request(req: &HttpRequest, payload: &mut Payload<P>) -> Self::Future {
|
||||||
let req2 = req.request().clone();
|
let req2 = req.clone();
|
||||||
let (limit, err) = req
|
let (limit, err) = req
|
||||||
.route_data::<JsonConfig>()
|
.route_data::<JsonConfig>()
|
||||||
.map(|c| (c.limit, c.ehandler.clone()))
|
.map(|c| (c.limit, c.ehandler.clone()))
|
||||||
.unwrap_or((32768, None));
|
.unwrap_or((32768, None));
|
||||||
|
|
||||||
Box::new(
|
Box::new(
|
||||||
JsonBody::new(req)
|
JsonBody::new(req, payload)
|
||||||
.limit(limit)
|
.limit(limit)
|
||||||
.map_err(move |e| {
|
.map_err(move |e| {
|
||||||
if let Some(err) = err {
|
if let Some(err) = err {
|
||||||
@ -264,22 +263,21 @@ impl Default for JsonConfig {
|
|||||||
///
|
///
|
||||||
/// * content type is not `application/json`
|
/// * content type is not `application/json`
|
||||||
/// * content length is greater than 256k
|
/// * content length is greater than 256k
|
||||||
pub struct JsonBody<T: HttpMessage, U> {
|
pub struct JsonBody<P, U> {
|
||||||
limit: usize,
|
limit: usize,
|
||||||
length: Option<usize>,
|
length: Option<usize>,
|
||||||
stream: Payload<T::Stream>,
|
stream: Payload<P>,
|
||||||
err: Option<JsonPayloadError>,
|
err: Option<JsonPayloadError>,
|
||||||
fut: Option<Box<Future<Item = U, Error = JsonPayloadError>>>,
|
fut: Option<Box<Future<Item = U, Error = JsonPayloadError>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, U> JsonBody<T, U>
|
impl<P, U> JsonBody<P, U>
|
||||||
where
|
where
|
||||||
T: HttpMessage,
|
P: Stream<Item = Bytes, Error = PayloadError> + 'static,
|
||||||
T::Stream: Stream<Item = Bytes, Error = PayloadError> + 'static,
|
|
||||||
U: DeserializeOwned + 'static,
|
U: DeserializeOwned + 'static,
|
||||||
{
|
{
|
||||||
/// Create `JsonBody` for request.
|
/// Create `JsonBody` for request.
|
||||||
pub fn new(req: &mut T) -> Self {
|
pub fn new(req: &HttpRequest, payload: &mut Payload<P>) -> Self {
|
||||||
// check content-type
|
// check content-type
|
||||||
let json = if let Ok(Some(mime)) = req.mime_type() {
|
let json = if let Ok(Some(mime)) = req.mime_type() {
|
||||||
mime.subtype() == mime::JSON || mime.suffix() == Some(mime::JSON)
|
mime.subtype() == mime::JSON || mime.suffix() == Some(mime::JSON)
|
||||||
@ -308,7 +306,7 @@ where
|
|||||||
JsonBody {
|
JsonBody {
|
||||||
limit: 262_144,
|
limit: 262_144,
|
||||||
length: len,
|
length: len,
|
||||||
stream: req.take_payload(),
|
stream: payload.take(),
|
||||||
fut: None,
|
fut: None,
|
||||||
err: None,
|
err: None,
|
||||||
}
|
}
|
||||||
@ -321,10 +319,9 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, U> Future for JsonBody<T, U>
|
impl<P, U> Future for JsonBody<P, U>
|
||||||
where
|
where
|
||||||
T: HttpMessage,
|
P: Stream<Item = Bytes, Error = PayloadError> + 'static,
|
||||||
T::Stream: Stream<Item = Bytes, Error = PayloadError> + 'static,
|
|
||||||
U: DeserializeOwned + 'static,
|
U: DeserializeOwned + 'static,
|
||||||
{
|
{
|
||||||
type Item = U;
|
type Item = U;
|
||||||
@ -410,7 +407,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_extract() {
|
fn test_extract() {
|
||||||
let mut req = TestRequest::default()
|
let (req, mut pl) = TestRequest::default()
|
||||||
.header(
|
.header(
|
||||||
header::CONTENT_TYPE,
|
header::CONTENT_TYPE,
|
||||||
header::HeaderValue::from_static("application/json"),
|
header::HeaderValue::from_static("application/json"),
|
||||||
@ -420,9 +417,9 @@ mod tests {
|
|||||||
header::HeaderValue::from_static("16"),
|
header::HeaderValue::from_static("16"),
|
||||||
)
|
)
|
||||||
.set_payload(Bytes::from_static(b"{\"name\": \"test\"}"))
|
.set_payload(Bytes::from_static(b"{\"name\": \"test\"}"))
|
||||||
.to_from();
|
.to_http_parts();
|
||||||
|
|
||||||
let s = block_on(Json::<MyObject>::from_request(&mut req)).unwrap();
|
let s = block_on(Json::<MyObject>::from_request(&req, &mut pl)).unwrap();
|
||||||
assert_eq!(s.name, "test");
|
assert_eq!(s.name, "test");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
s.into_inner(),
|
s.into_inner(),
|
||||||
@ -431,7 +428,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut req = TestRequest::default()
|
let (req, mut pl) = TestRequest::default()
|
||||||
.header(
|
.header(
|
||||||
header::CONTENT_TYPE,
|
header::CONTENT_TYPE,
|
||||||
header::HeaderValue::from_static("application/json"),
|
header::HeaderValue::from_static("application/json"),
|
||||||
@ -442,12 +439,13 @@ mod tests {
|
|||||||
)
|
)
|
||||||
.set_payload(Bytes::from_static(b"{\"name\": \"test\"}"))
|
.set_payload(Bytes::from_static(b"{\"name\": \"test\"}"))
|
||||||
.route_data(JsonConfig::default().limit(10))
|
.route_data(JsonConfig::default().limit(10))
|
||||||
.to_from();
|
.to_http_parts();
|
||||||
let s = block_on(Json::<MyObject>::from_request(&mut req));
|
|
||||||
|
let s = block_on(Json::<MyObject>::from_request(&req, &mut pl));
|
||||||
assert!(format!("{}", s.err().unwrap())
|
assert!(format!("{}", s.err().unwrap())
|
||||||
.contains("Json payload size is bigger than allowed."));
|
.contains("Json payload size is bigger than allowed."));
|
||||||
|
|
||||||
let mut req = TestRequest::default()
|
let (req, mut pl) = TestRequest::default()
|
||||||
.header(
|
.header(
|
||||||
header::CONTENT_TYPE,
|
header::CONTENT_TYPE,
|
||||||
header::HeaderValue::from_static("application/json"),
|
header::HeaderValue::from_static("application/json"),
|
||||||
@ -462,27 +460,27 @@ mod tests {
|
|||||||
.limit(10)
|
.limit(10)
|
||||||
.error_handler(|_, _| JsonPayloadError::ContentType.into()),
|
.error_handler(|_, _| JsonPayloadError::ContentType.into()),
|
||||||
)
|
)
|
||||||
.to_from();
|
.to_http_parts();
|
||||||
let s = block_on(Json::<MyObject>::from_request(&mut req));
|
let s = block_on(Json::<MyObject>::from_request(&req, &mut pl));
|
||||||
assert!(format!("{}", s.err().unwrap()).contains("Content type error"));
|
assert!(format!("{}", s.err().unwrap()).contains("Content type error"));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_json_body() {
|
fn test_json_body() {
|
||||||
let mut req = TestRequest::default().to_request();
|
let (req, mut pl) = TestRequest::default().to_http_parts();
|
||||||
let json = block_on(JsonBody::<_, MyObject>::new(&mut req));
|
let json = block_on(JsonBody::<_, MyObject>::new(&req, &mut pl));
|
||||||
assert!(json_eq(json.err().unwrap(), JsonPayloadError::ContentType));
|
assert!(json_eq(json.err().unwrap(), JsonPayloadError::ContentType));
|
||||||
|
|
||||||
let mut req = TestRequest::default()
|
let (req, mut pl) = TestRequest::default()
|
||||||
.header(
|
.header(
|
||||||
header::CONTENT_TYPE,
|
header::CONTENT_TYPE,
|
||||||
header::HeaderValue::from_static("application/text"),
|
header::HeaderValue::from_static("application/text"),
|
||||||
)
|
)
|
||||||
.to_request();
|
.to_http_parts();
|
||||||
let json = block_on(JsonBody::<_, MyObject>::new(&mut req));
|
let json = block_on(JsonBody::<_, MyObject>::new(&req, &mut pl));
|
||||||
assert!(json_eq(json.err().unwrap(), JsonPayloadError::ContentType));
|
assert!(json_eq(json.err().unwrap(), JsonPayloadError::ContentType));
|
||||||
|
|
||||||
let mut req = TestRequest::default()
|
let (req, mut pl) = TestRequest::default()
|
||||||
.header(
|
.header(
|
||||||
header::CONTENT_TYPE,
|
header::CONTENT_TYPE,
|
||||||
header::HeaderValue::from_static("application/json"),
|
header::HeaderValue::from_static("application/json"),
|
||||||
@ -491,12 +489,12 @@ mod tests {
|
|||||||
header::CONTENT_LENGTH,
|
header::CONTENT_LENGTH,
|
||||||
header::HeaderValue::from_static("10000"),
|
header::HeaderValue::from_static("10000"),
|
||||||
)
|
)
|
||||||
.to_request();
|
.to_http_parts();
|
||||||
|
|
||||||
let json = block_on(JsonBody::<_, MyObject>::new(&mut req).limit(100));
|
let json = block_on(JsonBody::<_, MyObject>::new(&req, &mut pl).limit(100));
|
||||||
assert!(json_eq(json.err().unwrap(), JsonPayloadError::Overflow));
|
assert!(json_eq(json.err().unwrap(), JsonPayloadError::Overflow));
|
||||||
|
|
||||||
let mut req = TestRequest::default()
|
let (req, mut pl) = TestRequest::default()
|
||||||
.header(
|
.header(
|
||||||
header::CONTENT_TYPE,
|
header::CONTENT_TYPE,
|
||||||
header::HeaderValue::from_static("application/json"),
|
header::HeaderValue::from_static("application/json"),
|
||||||
@ -506,9 +504,9 @@ mod tests {
|
|||||||
header::HeaderValue::from_static("16"),
|
header::HeaderValue::from_static("16"),
|
||||||
)
|
)
|
||||||
.set_payload(Bytes::from_static(b"{\"name\": \"test\"}"))
|
.set_payload(Bytes::from_static(b"{\"name\": \"test\"}"))
|
||||||
.to_request();
|
.to_http_parts();
|
||||||
|
|
||||||
let json = block_on(JsonBody::<_, MyObject>::new(&mut req));
|
let json = block_on(JsonBody::<_, MyObject>::new(&req, &mut pl));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
json.ok().unwrap(),
|
json.ok().unwrap(),
|
||||||
MyObject {
|
MyObject {
|
||||||
|
@ -6,8 +6,8 @@ use actix_http::error::{Error, ErrorNotFound};
|
|||||||
use actix_router::PathDeserializer;
|
use actix_router::PathDeserializer;
|
||||||
use serde::de;
|
use serde::de;
|
||||||
|
|
||||||
|
use crate::dev::Payload;
|
||||||
use crate::request::HttpRequest;
|
use crate::request::HttpRequest;
|
||||||
use crate::service::ServiceFromRequest;
|
|
||||||
use crate::FromRequest;
|
use crate::FromRequest;
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(PartialEq, Eq, PartialOrd, Ord)]
|
||||||
@ -66,15 +66,6 @@ impl<T> Path<T> {
|
|||||||
pub fn into_inner(self) -> T {
|
pub fn into_inner(self) -> T {
|
||||||
self.inner
|
self.inner
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extract path information from a request
|
|
||||||
pub fn extract(req: &HttpRequest) -> Result<Path<T>, de::value::Error>
|
|
||||||
where
|
|
||||||
T: de::DeserializeOwned,
|
|
||||||
{
|
|
||||||
de::Deserialize::deserialize(PathDeserializer::new(req.match_info()))
|
|
||||||
.map(|inner| Path { inner })
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> AsRef<T> for Path<T> {
|
impl<T> AsRef<T> for Path<T> {
|
||||||
@ -169,8 +160,10 @@ where
|
|||||||
type Future = Result<Self, Error>;
|
type Future = Result<Self, Error>;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future {
|
fn from_request(req: &HttpRequest, _: &mut Payload<P>) -> Self::Future {
|
||||||
Self::extract(req.request()).map_err(ErrorNotFound)
|
de::Deserialize::deserialize(PathDeserializer::new(req.match_info()))
|
||||||
|
.map(|inner| Path { inner })
|
||||||
|
.map_err(ErrorNotFound)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -185,25 +178,30 @@ mod tests {
|
|||||||
fn test_extract_path_single() {
|
fn test_extract_path_single() {
|
||||||
let resource = ResourceDef::new("/{value}/");
|
let resource = ResourceDef::new("/{value}/");
|
||||||
|
|
||||||
let mut req = TestRequest::with_uri("/32/").to_from();
|
let mut req = TestRequest::with_uri("/32/").to_srv_request();
|
||||||
resource.match_path(req.match_info_mut());
|
resource.match_path(req.match_info_mut());
|
||||||
|
|
||||||
assert_eq!(*Path::<i8>::from_request(&mut req).unwrap(), 32);
|
let (req, mut pl) = req.into_parts();
|
||||||
|
assert_eq!(*Path::<i8>::from_request(&req, &mut pl).unwrap(), 32);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_tuple_extract() {
|
fn test_tuple_extract() {
|
||||||
let resource = ResourceDef::new("/{key}/{value}/");
|
let resource = ResourceDef::new("/{key}/{value}/");
|
||||||
|
|
||||||
let mut req = TestRequest::with_uri("/name/user1/?id=test").to_from();
|
let mut req = TestRequest::with_uri("/name/user1/?id=test").to_srv_request();
|
||||||
resource.match_path(req.match_info_mut());
|
resource.match_path(req.match_info_mut());
|
||||||
|
|
||||||
let res = block_on(<(Path<(String, String)>,)>::from_request(&mut req)).unwrap();
|
let (req, mut pl) = req.into_parts();
|
||||||
|
let res =
|
||||||
|
block_on(<(Path<(String, String)>,)>::from_request(&req, &mut pl)).unwrap();
|
||||||
assert_eq!((res.0).0, "name");
|
assert_eq!((res.0).0, "name");
|
||||||
assert_eq!((res.0).1, "user1");
|
assert_eq!((res.0).1, "user1");
|
||||||
|
|
||||||
let res = block_on(
|
let res = block_on(
|
||||||
<(Path<(String, String)>, Path<(String, String)>)>::from_request(&mut req),
|
<(Path<(String, String)>, Path<(String, String)>)>::from_request(
|
||||||
|
&req, &mut pl,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!((res.0).0, "name");
|
assert_eq!((res.0).0, "name");
|
||||||
@ -211,7 +209,7 @@ mod tests {
|
|||||||
assert_eq!((res.1).0, "name");
|
assert_eq!((res.1).0, "name");
|
||||||
assert_eq!((res.1).1, "user1");
|
assert_eq!((res.1).1, "user1");
|
||||||
|
|
||||||
let () = <()>::from_request(&mut req).unwrap();
|
let () = <()>::from_request(&req, &mut pl).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -10,9 +10,10 @@ use futures::future::{err, Either, FutureResult};
|
|||||||
use futures::{Future, Poll, Stream};
|
use futures::{Future, Poll, Stream};
|
||||||
use mime::Mime;
|
use mime::Mime;
|
||||||
|
|
||||||
|
use crate::dev;
|
||||||
use crate::extract::FromRequest;
|
use crate::extract::FromRequest;
|
||||||
use crate::http::header;
|
use crate::http::header;
|
||||||
use crate::service::ServiceFromRequest;
|
use crate::request::HttpRequest;
|
||||||
|
|
||||||
/// Payload extractor returns request 's payload stream.
|
/// Payload extractor returns request 's payload stream.
|
||||||
///
|
///
|
||||||
@ -92,8 +93,8 @@ where
|
|||||||
type Future = Result<Payload, Error>;
|
type Future = Result<Payload, Error>;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future {
|
fn from_request(_: &HttpRequest, payload: &mut dev::Payload<P>) -> Self::Future {
|
||||||
let pl = match req.take_payload() {
|
let pl = match payload.take() {
|
||||||
crate::dev::Payload::Stream(s) => {
|
crate::dev::Payload::Stream(s) => {
|
||||||
let pl: Box<dyn Stream<Item = Bytes, Error = PayloadError>> =
|
let pl: Box<dyn Stream<Item = Bytes, Error = PayloadError>> =
|
||||||
Box::new(s);
|
Box::new(s);
|
||||||
@ -141,7 +142,7 @@ where
|
|||||||
Either<Box<Future<Item = Bytes, Error = Error>>, FutureResult<Bytes, Error>>;
|
Either<Box<Future<Item = Bytes, Error = Error>>, FutureResult<Bytes, Error>>;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future {
|
fn from_request(req: &HttpRequest, payload: &mut dev::Payload<P>) -> Self::Future {
|
||||||
let mut tmp;
|
let mut tmp;
|
||||||
let cfg = if let Some(cfg) = req.route_data::<PayloadConfig>() {
|
let cfg = if let Some(cfg) = req.route_data::<PayloadConfig>() {
|
||||||
cfg
|
cfg
|
||||||
@ -155,7 +156,9 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
let limit = cfg.limit;
|
let limit = cfg.limit;
|
||||||
Either::A(Box::new(HttpMessageBody::new(req).limit(limit).from_err()))
|
Either::A(Box::new(
|
||||||
|
HttpMessageBody::new(req, payload).limit(limit).from_err(),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -194,7 +197,7 @@ where
|
|||||||
Either<Box<Future<Item = String, Error = Error>>, FutureResult<String, Error>>;
|
Either<Box<Future<Item = String, Error = Error>>, FutureResult<String, Error>>;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future {
|
fn from_request(req: &HttpRequest, payload: &mut dev::Payload<P>) -> Self::Future {
|
||||||
let mut tmp;
|
let mut tmp;
|
||||||
let cfg = if let Some(cfg) = req.route_data::<PayloadConfig>() {
|
let cfg = if let Some(cfg) = req.route_data::<PayloadConfig>() {
|
||||||
cfg
|
cfg
|
||||||
@ -216,7 +219,7 @@ where
|
|||||||
let limit = cfg.limit;
|
let limit = cfg.limit;
|
||||||
|
|
||||||
Either::A(Box::new(
|
Either::A(Box::new(
|
||||||
HttpMessageBody::new(req)
|
HttpMessageBody::new(req, payload)
|
||||||
.limit(limit)
|
.limit(limit)
|
||||||
.from_err()
|
.from_err()
|
||||||
.and_then(move |body| {
|
.and_then(move |body| {
|
||||||
@ -260,7 +263,7 @@ impl PayloadConfig {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_mimetype<P>(&self, req: &ServiceFromRequest<P>) -> Result<(), Error> {
|
fn check_mimetype(&self, req: &HttpRequest) -> Result<(), Error> {
|
||||||
// check content-type
|
// check content-type
|
||||||
if let Some(ref mt) = self.mimetype {
|
if let Some(ref mt) = self.mimetype {
|
||||||
match req.mime_type() {
|
match req.mime_type() {
|
||||||
@ -297,21 +300,20 @@ impl Default for PayloadConfig {
|
|||||||
/// By default only 256Kb payload reads to a memory, then
|
/// By default only 256Kb payload reads to a memory, then
|
||||||
/// `PayloadError::Overflow` get returned. Use `MessageBody::limit()`
|
/// `PayloadError::Overflow` get returned. Use `MessageBody::limit()`
|
||||||
/// method to change upper limit.
|
/// method to change upper limit.
|
||||||
pub struct HttpMessageBody<T: HttpMessage> {
|
pub struct HttpMessageBody<P> {
|
||||||
limit: usize,
|
limit: usize,
|
||||||
length: Option<usize>,
|
length: Option<usize>,
|
||||||
stream: actix_http::Payload<T::Stream>,
|
stream: dev::Payload<P>,
|
||||||
err: Option<PayloadError>,
|
err: Option<PayloadError>,
|
||||||
fut: Option<Box<Future<Item = Bytes, Error = PayloadError>>>,
|
fut: Option<Box<Future<Item = Bytes, Error = PayloadError>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> HttpMessageBody<T>
|
impl<P> HttpMessageBody<P>
|
||||||
where
|
where
|
||||||
T: HttpMessage,
|
P: Stream<Item = Bytes, Error = PayloadError>,
|
||||||
T::Stream: Stream<Item = Bytes, Error = PayloadError>,
|
|
||||||
{
|
{
|
||||||
/// Create `MessageBody` for request.
|
/// Create `MessageBody` for request.
|
||||||
pub fn new(req: &mut T) -> HttpMessageBody<T> {
|
pub fn new(req: &HttpRequest, payload: &mut dev::Payload<P>) -> HttpMessageBody<P> {
|
||||||
let mut len = None;
|
let mut len = None;
|
||||||
if let Some(l) = req.headers().get(&header::CONTENT_LENGTH) {
|
if let Some(l) = req.headers().get(&header::CONTENT_LENGTH) {
|
||||||
if let Ok(s) = l.to_str() {
|
if let Ok(s) = l.to_str() {
|
||||||
@ -326,7 +328,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
HttpMessageBody {
|
HttpMessageBody {
|
||||||
stream: req.take_payload(),
|
stream: payload.take(),
|
||||||
limit: 262_144,
|
limit: 262_144,
|
||||||
length: len,
|
length: len,
|
||||||
fut: None,
|
fut: None,
|
||||||
@ -342,7 +344,7 @@ where
|
|||||||
|
|
||||||
fn err(e: PayloadError) -> Self {
|
fn err(e: PayloadError) -> Self {
|
||||||
HttpMessageBody {
|
HttpMessageBody {
|
||||||
stream: actix_http::Payload::None,
|
stream: dev::Payload::None,
|
||||||
limit: 262_144,
|
limit: 262_144,
|
||||||
fut: None,
|
fut: None,
|
||||||
err: Some(e),
|
err: Some(e),
|
||||||
@ -351,10 +353,9 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Future for HttpMessageBody<T>
|
impl<P> Future for HttpMessageBody<P>
|
||||||
where
|
where
|
||||||
T: HttpMessage,
|
P: Stream<Item = Bytes, Error = PayloadError> + 'static,
|
||||||
T::Stream: Stream<Item = Bytes, Error = PayloadError> + 'static,
|
|
||||||
{
|
{
|
||||||
type Item = Bytes;
|
type Item = Bytes;
|
||||||
type Error = PayloadError;
|
type Error = PayloadError;
|
||||||
@ -403,7 +404,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_payload_config() {
|
fn test_payload_config() {
|
||||||
let req = TestRequest::default().to_from();
|
let req = TestRequest::default().to_http_request();
|
||||||
let cfg = PayloadConfig::default().mimetype(mime::APPLICATION_JSON);
|
let cfg = PayloadConfig::default().mimetype(mime::APPLICATION_JSON);
|
||||||
assert!(cfg.check_mimetype(&req).is_err());
|
assert!(cfg.check_mimetype(&req).is_err());
|
||||||
|
|
||||||
@ -411,62 +412,64 @@ mod tests {
|
|||||||
header::CONTENT_TYPE,
|
header::CONTENT_TYPE,
|
||||||
"application/x-www-form-urlencoded",
|
"application/x-www-form-urlencoded",
|
||||||
)
|
)
|
||||||
.to_from();
|
.to_http_request();
|
||||||
assert!(cfg.check_mimetype(&req).is_err());
|
assert!(cfg.check_mimetype(&req).is_err());
|
||||||
|
|
||||||
let req =
|
let req = TestRequest::with_header(header::CONTENT_TYPE, "application/json")
|
||||||
TestRequest::with_header(header::CONTENT_TYPE, "application/json").to_from();
|
.to_http_request();
|
||||||
assert!(cfg.check_mimetype(&req).is_ok());
|
assert!(cfg.check_mimetype(&req).is_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_bytes() {
|
fn test_bytes() {
|
||||||
let mut req = TestRequest::with_header(header::CONTENT_LENGTH, "11")
|
let (req, mut pl) = TestRequest::with_header(header::CONTENT_LENGTH, "11")
|
||||||
.set_payload(Bytes::from_static(b"hello=world"))
|
.set_payload(Bytes::from_static(b"hello=world"))
|
||||||
.to_from();
|
.to_http_parts();
|
||||||
|
|
||||||
let s = block_on(Bytes::from_request(&mut req)).unwrap();
|
let s = block_on(Bytes::from_request(&req, &mut pl)).unwrap();
|
||||||
assert_eq!(s, Bytes::from_static(b"hello=world"));
|
assert_eq!(s, Bytes::from_static(b"hello=world"));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_string() {
|
fn test_string() {
|
||||||
let mut req = TestRequest::with_header(header::CONTENT_LENGTH, "11")
|
let (req, mut pl) = TestRequest::with_header(header::CONTENT_LENGTH, "11")
|
||||||
.set_payload(Bytes::from_static(b"hello=world"))
|
.set_payload(Bytes::from_static(b"hello=world"))
|
||||||
.to_from();
|
.to_http_parts();
|
||||||
|
|
||||||
let s = block_on(String::from_request(&mut req)).unwrap();
|
let s = block_on(String::from_request(&req, &mut pl)).unwrap();
|
||||||
assert_eq!(s, "hello=world");
|
assert_eq!(s, "hello=world");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_message_body() {
|
fn test_message_body() {
|
||||||
let mut req =
|
let (req, mut pl) = TestRequest::with_header(header::CONTENT_LENGTH, "xxxx")
|
||||||
TestRequest::with_header(header::CONTENT_LENGTH, "xxxx").to_request();
|
.to_srv_request()
|
||||||
let res = block_on(HttpMessageBody::new(&mut req));
|
.into_parts();
|
||||||
|
let res = block_on(HttpMessageBody::new(&req, &mut pl));
|
||||||
match res.err().unwrap() {
|
match res.err().unwrap() {
|
||||||
PayloadError::UnknownLength => (),
|
PayloadError::UnknownLength => (),
|
||||||
_ => unreachable!("error"),
|
_ => unreachable!("error"),
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut req =
|
let (req, mut pl) = TestRequest::with_header(header::CONTENT_LENGTH, "1000000")
|
||||||
TestRequest::with_header(header::CONTENT_LENGTH, "1000000").to_request();
|
.to_srv_request()
|
||||||
let res = block_on(HttpMessageBody::new(&mut req));
|
.into_parts();
|
||||||
|
let res = block_on(HttpMessageBody::new(&req, &mut pl));
|
||||||
match res.err().unwrap() {
|
match res.err().unwrap() {
|
||||||
PayloadError::Overflow => (),
|
PayloadError::Overflow => (),
|
||||||
_ => unreachable!("error"),
|
_ => unreachable!("error"),
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut req = TestRequest::default()
|
let (req, mut pl) = TestRequest::default()
|
||||||
.set_payload(Bytes::from_static(b"test"))
|
.set_payload(Bytes::from_static(b"test"))
|
||||||
.to_request();
|
.to_http_parts();
|
||||||
let res = block_on(HttpMessageBody::new(&mut req));
|
let res = block_on(HttpMessageBody::new(&req, &mut pl));
|
||||||
assert_eq!(res.ok().unwrap(), Bytes::from_static(b"test"));
|
assert_eq!(res.ok().unwrap(), Bytes::from_static(b"test"));
|
||||||
|
|
||||||
let mut req = TestRequest::default()
|
let (req, mut pl) = TestRequest::default()
|
||||||
.set_payload(Bytes::from_static(b"11111111111111"))
|
.set_payload(Bytes::from_static(b"11111111111111"))
|
||||||
.to_request();
|
.to_http_parts();
|
||||||
let res = block_on(HttpMessageBody::new(&mut req).limit(5));
|
let res = block_on(HttpMessageBody::new(&req, &mut pl).limit(5));
|
||||||
match res.err().unwrap() {
|
match res.err().unwrap() {
|
||||||
PayloadError::Overflow => (),
|
PayloadError::Overflow => (),
|
||||||
_ => unreachable!("error"),
|
_ => unreachable!("error"),
|
||||||
|
@ -6,8 +6,9 @@ use actix_http::error::Error;
|
|||||||
use serde::de;
|
use serde::de;
|
||||||
use serde_urlencoded;
|
use serde_urlencoded;
|
||||||
|
|
||||||
|
use crate::dev::Payload;
|
||||||
use crate::extract::FromRequest;
|
use crate::extract::FromRequest;
|
||||||
use crate::service::ServiceFromRequest;
|
use crate::request::HttpRequest;
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(PartialEq, Eq, PartialOrd, Ord)]
|
||||||
/// Extract typed information from from the request's query.
|
/// Extract typed information from from the request's query.
|
||||||
@ -118,8 +119,8 @@ where
|
|||||||
type Future = Result<Self, Error>;
|
type Future = Result<Self, Error>;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future {
|
fn from_request(req: &HttpRequest, _: &mut Payload<P>) -> Self::Future {
|
||||||
serde_urlencoded::from_str::<T>(req.request().query_string())
|
serde_urlencoded::from_str::<T>(req.query_string())
|
||||||
.map(|val| Ok(Query(val)))
|
.map(|val| Ok(Query(val)))
|
||||||
.unwrap_or_else(|e| Err(e.into()))
|
.unwrap_or_else(|e| Err(e.into()))
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user