1
0
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:
Nikolay Kim 2019-04-07 14:43:07 -07:00
parent 3c650ca194
commit 75b213a6f0
18 changed files with 298 additions and 352 deletions

View File

@ -14,6 +14,8 @@
### Changed ### Changed
* `FromRequest` trait refactoring
* Move multipart support to actix-multipart crate * Move multipart support to actix-multipart crate

View File

@ -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())
} }
} }

View File

@ -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))
} }
} }

View File

@ -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()));

View File

@ -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 {

View File

@ -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());
} }
} }

View File

@ -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)))
} }
} }

View File

@ -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;

View File

@ -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()))
} }
} }

View File

@ -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())
} }
} }

View File

@ -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>;

View File

@ -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>,

View File

@ -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

View File

@ -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 {

View File

@ -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 {

View File

@ -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();
} }
} }

View File

@ -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"),

View File

@ -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()))
} }