1
0
mirror of https://github.com/fafhrd91/actix-web synced 2024-11-24 00:21:08 +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
* `FromRequest` trait refactoring
* 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::{IntoNewService, NewService, Service};
use actix_web::dev::{
HttpServiceFactory, Payload, ResourceDef, ServiceConfig, ServiceFromRequest,
ServiceRequest, ServiceResponse,
HttpServiceFactory, Payload, ResourceDef, ServiceConfig, ServiceRequest,
ServiceResponse,
};
use actix_web::error::{BlockingError, Error, ErrorInternalServerError};
use actix_web::http::header::DispositionType;
@ -551,8 +551,8 @@ impl<P> FromRequest<P> for PathBufWrp {
type Error = UriSegmentError;
type Future = Result<Self, Self::Error>;
fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future {
PathBufWrp::get_pathbuf(req.request().match_info().path())
fn from_request(req: &HttpRequest, _: &mut Payload<P>) -> Self::Future {
PathBufWrp::get_pathbuf(req.match_info().path())
}
}

View File

@ -2,10 +2,8 @@
use bytes::Bytes;
use futures::Stream;
use actix_web::dev::ServiceFromRequest;
use actix_web::error::{Error, PayloadError};
use actix_web::FromRequest;
use actix_web::HttpMessage;
use actix_web::{dev::Payload, FromRequest, HttpRequest};
use crate::server::Multipart;
@ -50,8 +48,7 @@ where
type Future = Result<Multipart, Error>;
#[inline]
fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future {
let pl = req.take_payload();
Ok(Multipart::new(req.headers(), pl))
fn from_request(req: &HttpRequest, payload: &mut Payload<P>) -> Self::Future {
Ok(Multipart::new(req.headers(), payload.take()))
}
}

View File

@ -45,8 +45,8 @@
use std::cell::RefCell;
use std::rc::Rc;
use actix_web::dev::{ServiceFromRequest, ServiceRequest, ServiceResponse};
use actix_web::{Error, FromRequest, HttpMessage};
use actix_web::dev::{Extensions, Payload, ServiceRequest, ServiceResponse};
use actix_web::{Error, FromRequest, HttpMessage, HttpRequest};
use hashbrown::HashMap;
use serde::de::DeserializeOwned;
use serde::Serialize;
@ -123,7 +123,7 @@ impl Session {
data: impl Iterator<Item = (String, String)>,
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();
inner.state.extend(data);
}
@ -144,12 +144,12 @@ impl Session {
}
}
fn get_session<R: HttpMessage>(req: R) -> Session {
if let Some(s_impl) = req.extensions().get::<Rc<RefCell<SessionInner>>>() {
fn get_session(extensions: &mut Extensions) -> Session {
if let Some(s_impl) = extensions.get::<Rc<RefCell<SessionInner>>>() {
return Session(Rc::clone(&s_impl));
}
let inner = Rc::new(RefCell::new(SessionInner::default()));
req.extensions_mut().insert(inner.clone());
extensions.insert(inner.clone());
Session(inner)
}
}
@ -177,8 +177,8 @@ impl<P> FromRequest<P> for Session {
type Future = Result<Session, Error>;
#[inline]
fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future {
Ok(Session::get_session(req))
fn from_request(req: &HttpRequest, _: &mut Payload<P>) -> Self::Future {
Ok(Session::get_session(&mut *req.extensions_mut()))
}
}
@ -196,7 +196,7 @@ mod tests {
vec![("key".to_string(), "\"value\"".to_string())].into_iter(),
&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();
assert_eq!(res, Some("value".to_string()));

View File

@ -5,8 +5,9 @@ use actix_http::error::{Error, ErrorInternalServerError};
use actix_http::Extensions;
use futures::{Async, Future, IntoFuture, Poll};
use crate::dev::Payload;
use crate::extract::FromRequest;
use crate::service::ServiceFromRequest;
use crate::request::HttpRequest;
/// Application data factory
pub(crate) trait DataFactory {
@ -91,8 +92,8 @@ impl<T: 'static, P> FromRequest<P> for Data<T> {
type Future = Result<Self, Error>;
#[inline]
fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future {
if let Some(st) = req.request().config().extensions().get::<Data<T>>() {
fn from_request(req: &HttpRequest, _: &mut Payload<P>) -> Self::Future {
if let Some(st) = req.app_config().extensions().get::<Data<T>>() {
Ok(st.clone())
} else {
Err(ErrorInternalServerError(
@ -230,7 +231,7 @@ impl<T: 'static, P> FromRequest<P> for RouteData<T> {
type Future = Result<Self, Error>;
#[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>() {
Ok(st.clone())
} else {

View File

@ -4,7 +4,8 @@ use actix_http::error::Error;
use futures::future::ok;
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.
///
@ -17,7 +18,14 @@ pub trait FromRequest<P>: Sized {
type Future: IntoFuture<Item = Self, Error = Self::Error>;
/// 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
@ -28,7 +36,7 @@ pub trait FromRequest<P>: Sized {
///
/// ```rust
/// # #[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 rand;
///
@ -41,7 +49,7 @@ pub trait FromRequest<P>: Sized {
/// type Error = 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() {
/// Ok(Thing { name: "thingy".into() })
/// } else {
@ -76,14 +84,18 @@ where
type Future = Box<Future<Item = Option<T>, Error = Error>>;
#[inline]
fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future {
Box::new(T::from_request(req).into_future().then(|r| match r {
Ok(v) => future::ok(Some(v)),
Err(e) => {
log::debug!("Error for Option<T> extractor: {}", e.into());
future::ok(None)
}
}))
fn from_request(req: &HttpRequest, payload: &mut Payload<P>) -> Self::Future {
Box::new(
T::from_request(req, payload)
.into_future()
.then(|r| match r {
Ok(v) => future::ok(Some(v)),
Err(e) => {
log::debug!("Error for Option<T> extractor: {}", e.into());
future::ok(None)
}
}),
)
}
}
@ -95,7 +107,7 @@ where
///
/// ```rust
/// # #[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 rand;
///
@ -108,7 +120,7 @@ where
/// type Error = 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() {
/// Ok(Thing { name: "thingy".into() })
/// } else {
@ -141,11 +153,15 @@ where
type Future = Box<Future<Item = Result<T, T::Error>, Error = Error>>;
#[inline]
fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future {
Box::new(T::from_request(req).into_future().then(|res| match res {
Ok(v) => ok(Ok(v)),
Err(e) => ok(Err(e)),
}))
fn from_request(req: &HttpRequest, payload: &mut Payload<P>) -> Self::Future {
Box::new(
T::from_request(req, payload)
.into_future()
.then(|res| match res {
Ok(v) => ok(Ok(v)),
Err(e) => ok(Err(e)),
}),
)
}
}
@ -154,7 +170,7 @@ impl<P> FromRequest<P> for () {
type Error = Error;
type Future = Result<(), Error>;
fn from_request(_req: &mut ServiceFromRequest<P>) -> Self::Future {
fn from_request(_: &HttpRequest, _: &mut Payload<P>) -> Self::Future {
Ok(())
}
}
@ -168,10 +184,10 @@ macro_rules! tuple_from_req ({$fut_type:ident, $(($n:tt, $T:ident)),+} => {
type Error = Error;
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 {
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]
fn test_option() {
let mut req = TestRequest::with_header(
let (req, mut pl) = TestRequest::with_header(
header::CONTENT_TYPE,
"application/x-www-form-urlencoded",
)
.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);
let mut req = TestRequest::with_header(
let (req, mut pl) = TestRequest::with_header(
header::CONTENT_TYPE,
"application/x-www-form-urlencoded",
)
.header(header::CONTENT_LENGTH, "9")
.set_payload(Bytes::from_static(b"hello=world"))
.to_from();
.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,
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,
"application/x-www-form-urlencoded",
)
.header(header::CONTENT_LENGTH, "9")
.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);
}
#[test]
fn test_result() {
let mut req = TestRequest::with_header(
let (req, mut pl) = TestRequest::with_header(
header::CONTENT_TYPE,
"application/x-www-form-urlencoded",
)
.header(header::CONTENT_LENGTH, "11")
.set_payload(Bytes::from_static(b"hello=world"))
.to_from();
.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();
assert_eq!(
@ -305,15 +321,16 @@ mod tests {
})
);
let mut req = TestRequest::with_header(
let (req, mut pl) = TestRequest::with_header(
header::CONTENT_TYPE,
"application/x-www-form-urlencoded",
)
.header(header::CONTENT_LENGTH, "9")
.set_payload(Bytes::from_static(b"bye=world"))
.to_from();
.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());
}
@ -336,37 +353,38 @@ mod tests {
#[test]
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}/");
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.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.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");
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}/");
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.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.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[1], "32".to_owned());
}
}

View File

@ -2,7 +2,7 @@ use std::cell::RefCell;
use std::marker::PhantomData;
use std::rc::Rc;
use actix_http::{Error, Extensions, Response};
use actix_http::{Error, Extensions, Payload, Response};
use actix_service::{NewService, Service, Void};
use futures::future::{ok, FutureResult};
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::request::HttpRequest;
use crate::responder::Responder;
use crate::service::{ServiceFromRequest, ServiceRequest, ServiceResponse};
use crate::service::{ServiceRequest, ServiceResponse};
/// Handler converter factory
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> {
type Request = ServiceRequest<P>;
type Response = (T, HttpRequest);
type Error = (Error, ServiceFromRequest<P>);
type Error = (Error, ServiceRequest<P>);
type InitError = ();
type Service = ExtractService<P, T>;
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> {
type Request = ServiceRequest<P>;
type Response = (T, HttpRequest);
type Error = (Error, ServiceFromRequest<P>);
type Error = (Error, ServiceRequest<P>);
type Future = ExtractResponse<P, T>;
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 {
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 {
fut: T::from_request(&mut req).into_future(),
req: Some(req),
fut,
req: Some((req, payload)),
}
}
}
pub struct ExtractResponse<P, T: FromRequest<P>> {
req: Option<ServiceFromRequest<P>>,
req: Option<(HttpRequest, Payload<P>)>,
fut: <T::Future as IntoFuture>::Future,
}
impl<P, T: FromRequest<P>> Future for ExtractResponse<P, T> {
type Item = (T, HttpRequest);
type Error = (Error, ServiceFromRequest<P>);
type Error = (Error, ServiceRequest<P>);
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
let item = try_ready!(self
.fut
.poll()
.map_err(|e| (e.into(), self.req.take().unwrap())));
let item = try_ready!(self.fut.poll().map_err(|e| {
let (req, payload) = self.req.take().unwrap();
let req = ServiceRequest::from_parts(req, payload);
(e.into(), req)
}));
let req = self.req.take().unwrap();
let req = req.into_request();
Ok(Async::Ready((item, req)))
Ok(Async::Ready((item, self.req.take().unwrap().0)))
}
}

View File

@ -138,9 +138,7 @@ pub mod dev {
pub use crate::config::{AppConfig, ServiceConfig};
pub use crate::info::ConnectionInfo;
pub use crate::rmap::ResourceMap;
pub use crate::service::{
HttpServiceFactory, ServiceFromRequest, ServiceRequest, ServiceResponse,
};
pub use crate::service::{HttpServiceFactory, ServiceRequest, ServiceResponse};
pub use crate::types::form::UrlEncoded;
pub use crate::types::json::JsonBody;
pub use crate::types::readlines::Readlines;

View File

@ -58,10 +58,8 @@ use time::Duration;
use crate::cookie::{Cookie, CookieJar, Key, SameSite};
use crate::error::{Error, Result};
use crate::http::header::{self, HeaderValue};
use crate::request::HttpRequest;
use crate::service::{ServiceFromRequest, ServiceRequest, ServiceResponse};
use crate::FromRequest;
use crate::HttpMessage;
use crate::service::{ServiceRequest, ServiceResponse};
use crate::{dev::Payload, FromRequest, HttpMessage, HttpRequest};
/// 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>;
#[inline]
fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future {
Ok(Identity(req.request().clone()))
fn from_request(req: &HttpRequest, _: &mut Payload<P>) -> Self::Future {
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 crate::config::AppConfig;
use crate::data::Data;
use crate::data::{Data, RouteData};
use crate::error::UrlGenerationError;
use crate::extract::FromRequest;
use crate::info::ConnectionInfo;
use crate::rmap::ResourceMap;
use crate::service::ServiceFromRequest;
#[derive(Clone)]
/// An HTTP Request
@ -21,6 +20,7 @@ pub struct HttpRequest {
pub(crate) path: Path<Url>,
rmap: Rc<ResourceMap>,
config: AppConfig,
route_data: Option<Rc<Extensions>>,
}
impl HttpRequest {
@ -36,6 +36,7 @@ impl HttpRequest {
path,
rmap,
config,
route_data: None,
}
}
}
@ -100,22 +101,6 @@ impl HttpRequest {
&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
#[inline]
pub fn extensions(&self) -> Ref<Extensions> {
@ -171,7 +156,37 @@ impl HttpRequest {
/// Get *ConnectionInfo* for the current request.
#[inline]
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>;
#[inline]
fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future {
Ok(req.request().clone())
fn from_request(req: &HttpRequest, _: &mut Payload<P>) -> Self::Future {
Ok(req.clone())
}
}

View File

@ -11,7 +11,7 @@ use crate::extract::FromRequest;
use crate::guard::{self, Guard};
use crate::handler::{AsyncFactory, AsyncHandler, Extract, Factory, Handler};
use crate::responder::Responder;
use crate::service::{ServiceFromRequest, ServiceRequest, ServiceResponse};
use crate::service::{ServiceRequest, ServiceResponse};
use crate::HttpResponse;
type BoxedRouteService<Req, Res> = Box<
@ -317,7 +317,7 @@ impl<P: 'static> Route<P> {
struct RouteNewService<P, T>
where
T: NewService<Request = ServiceRequest<P>, Error = (Error, ServiceFromRequest<P>)>,
T: NewService<Request = ServiceRequest<P>, Error = (Error, ServiceRequest<P>)>,
{
service: T,
_t: PhantomData<P>,
@ -328,7 +328,7 @@ where
T: NewService<
Request = ServiceRequest<P>,
Response = ServiceResponse,
Error = (Error, ServiceFromRequest<P>),
Error = (Error, ServiceRequest<P>),
>,
T::Future: 'static,
T::Service: 'static,
@ -347,7 +347,7 @@ where
T: NewService<
Request = ServiceRequest<P>,
Response = ServiceResponse,
Error = (Error, ServiceFromRequest<P>),
Error = (Error, ServiceRequest<P>),
>,
T::Future: 'static,
T::Service: 'static,
@ -388,7 +388,7 @@ where
T: Service<
Request = ServiceRequest<P>,
Response = ServiceResponse,
Error = (Error, ServiceFromRequest<P>),
Error = (Error, 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 crate::config::{AppConfig, ServiceConfig};
use crate::data::{Data, RouteData};
use crate::data::Data;
use crate::request::HttpRequest;
use crate::rmap::ResourceMap;
@ -171,13 +171,13 @@ impl<P> ServiceRequest<P> {
/// Service configuration
#[inline]
pub fn app_config(&self) -> &AppConfig {
self.req.config()
self.req.app_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.req.config().extensions().get::<Data<T>>() {
if let Some(st) = self.req.app_config().extensions().get::<Data<T>>() {
Some(st.clone())
} else {
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> {
request: HttpRequest,
response: Response<B>,

View File

@ -16,9 +16,9 @@ use futures::future::{lazy, Future};
use crate::config::{AppConfig, AppConfigInner};
use crate::data::RouteData;
use crate::dev::Body;
use crate::dev::{Body, Payload};
use crate::rmap::ResourceMap;
use crate::service::{ServiceFromRequest, ServiceRequest, ServiceResponse};
use crate::service::{ServiceRequest, ServiceResponse};
use crate::{Error, HttpRequest, HttpResponse};
thread_local! {
@ -319,6 +319,11 @@ impl TestRequest {
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
pub fn to_srv_request(mut self) -> ServiceRequest<PayloadStream> {
let req = self.req.finish();
@ -336,36 +341,36 @@ impl TestRequest {
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
pub fn to_http_request(mut self) -> HttpRequest {
let req = self.req.finish();
ServiceRequest::new(
let mut req = ServiceRequest::new(
Path::new(Url::new(req.uri().clone())),
req,
Rc::new(self.rmap),
AppConfig::new(self.config),
)
.into_parts()
.0
.0;
req.set_route_data(Some(Rc::new(self.route_data)));
req
}
/// Complete request creation and generate `ServiceFromRequest` instance
pub fn to_from(mut self) -> ServiceFromRequest<PayloadStream> {
/// Complete request creation and generate `HttpRequest` and `Payload` instances
pub fn to_http_parts(mut self) -> (HttpRequest, Payload) {
let req = self.req.finish();
let req = ServiceRequest::new(
let (mut req, pl) = ServiceRequest::new(
Path::new(Url::new(req.uri().clone())),
req,
Rc::new(self.rmap),
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

View File

@ -16,7 +16,6 @@ use crate::error::UrlencodedError;
use crate::extract::FromRequest;
use crate::http::header::CONTENT_LENGTH;
use crate::request::HttpRequest;
use crate::service::ServiceFromRequest;
#[derive(PartialEq, Eq, PartialOrd, Ord)]
/// Extract typed information from the request's body.
@ -79,15 +78,15 @@ where
type Future = Box<Future<Item = Self, Error = Error>>;
#[inline]
fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future {
let req2 = req.request().clone();
fn from_request(req: &HttpRequest, payload: &mut Payload<P>) -> Self::Future {
let req2 = req.clone();
let (limit, err) = req
.route_data::<FormConfig>()
.map(|c| (c.limit, c.ehandler.clone()))
.unwrap_or((16384, None));
Box::new(
UrlEncoded::new(req)
UrlEncoded::new(req, payload)
.limit(limit)
.map_err(move |e| {
if let Some(err) = err {
@ -183,8 +182,8 @@ impl Default for FormConfig {
/// * content type is not `application/x-www-form-urlencoded`
/// * content-length is greater than 32k
///
pub struct UrlEncoded<T: HttpMessage, U> {
stream: Payload<T::Stream>,
pub struct UrlEncoded<P, U> {
stream: Payload<P>,
limit: usize,
length: Option<usize>,
encoding: EncodingRef,
@ -192,13 +191,12 @@ pub struct UrlEncoded<T: HttpMessage, U> {
fut: Option<Box<Future<Item = U, Error = UrlencodedError>>>,
}
impl<T, U> UrlEncoded<T, U>
impl<P, U> UrlEncoded<P, U>
where
T: HttpMessage,
T::Stream: Stream<Item = Bytes, Error = PayloadError>,
P: Stream<Item = Bytes, Error = PayloadError>,
{
/// 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
if req.content_type().to_lowercase() != "application/x-www-form-urlencoded" {
return Self::err(UrlencodedError::ContentType);
@ -223,7 +221,7 @@ where
UrlEncoded {
encoding,
stream: req.take_payload(),
stream: payload.take(),
limit: 32_768,
length: len,
fut: None,
@ -249,10 +247,9 @@ where
}
}
impl<T, U> Future for UrlEncoded<T, U>
impl<P, U> Future for UrlEncoded<P, U>
where
T: HttpMessage,
T::Stream: Stream<Item = Bytes, Error = PayloadError> + 'static,
P: Stream<Item = Bytes, Error = PayloadError> + 'static,
U: DeserializeOwned + 'static,
{
type Item = U;
@ -320,13 +317,13 @@ mod tests {
#[test]
fn test_form() {
let mut req =
let (req, mut pl) =
TestRequest::with_header(CONTENT_TYPE, "application/x-www-form-urlencoded")
.header(CONTENT_LENGTH, "11")
.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");
}
@ -354,36 +351,36 @@ mod tests {
#[test]
fn test_urlencoded_error() {
let mut req =
let (req, mut pl) =
TestRequest::with_header(CONTENT_TYPE, "application/x-www-form-urlencoded")
.header(CONTENT_LENGTH, "xxxx")
.to_request();
let info = block_on(UrlEncoded::<_, Info>::new(&mut req));
.to_http_parts();
let info = block_on(UrlEncoded::<_, Info>::new(&req, &mut pl));
assert!(eq(info.err().unwrap(), UrlencodedError::UnknownLength));
let mut req =
let (req, mut pl) =
TestRequest::with_header(CONTENT_TYPE, "application/x-www-form-urlencoded")
.header(CONTENT_LENGTH, "1000000")
.to_request();
let info = block_on(UrlEncoded::<_, Info>::new(&mut req));
.to_http_parts();
let info = block_on(UrlEncoded::<_, Info>::new(&req, &mut pl));
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")
.to_request();
let info = block_on(UrlEncoded::<_, Info>::new(&mut req));
.to_http_parts();
let info = block_on(UrlEncoded::<_, Info>::new(&req, &mut pl));
assert!(eq(info.err().unwrap(), UrlencodedError::ContentType));
}
#[test]
fn test_urlencoded() {
let mut req =
let (req, mut pl) =
TestRequest::with_header(CONTENT_TYPE, "application/x-www-form-urlencoded")
.header(CONTENT_LENGTH, "11")
.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!(
info,
Info {
@ -391,15 +388,15 @@ mod tests {
}
);
let mut req = TestRequest::with_header(
let (req, mut pl) = TestRequest::with_header(
CONTENT_TYPE,
"application/x-www-form-urlencoded; charset=utf-8",
)
.header(CONTENT_LENGTH, "11")
.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!(
info,
Info {

View File

@ -16,7 +16,6 @@ use crate::error::{Error, JsonPayloadError, PayloadError};
use crate::extract::FromRequest;
use crate::request::HttpRequest;
use crate::responder::Responder;
use crate::service::ServiceFromRequest;
/// Json helper
///
@ -173,15 +172,15 @@ where
type Future = Box<Future<Item = Self, Error = Error>>;
#[inline]
fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future {
let req2 = req.request().clone();
fn from_request(req: &HttpRequest, payload: &mut Payload<P>) -> Self::Future {
let req2 = req.clone();
let (limit, err) = req
.route_data::<JsonConfig>()
.map(|c| (c.limit, c.ehandler.clone()))
.unwrap_or((32768, None));
Box::new(
JsonBody::new(req)
JsonBody::new(req, payload)
.limit(limit)
.map_err(move |e| {
if let Some(err) = err {
@ -264,22 +263,21 @@ impl Default for JsonConfig {
///
/// * content type is not `application/json`
/// * content length is greater than 256k
pub struct JsonBody<T: HttpMessage, U> {
pub struct JsonBody<P, U> {
limit: usize,
length: Option<usize>,
stream: Payload<T::Stream>,
stream: Payload<P>,
err: Option<JsonPayloadError>,
fut: Option<Box<Future<Item = U, Error = JsonPayloadError>>>,
}
impl<T, U> JsonBody<T, U>
impl<P, U> JsonBody<P, U>
where
T: HttpMessage,
T::Stream: Stream<Item = Bytes, Error = PayloadError> + 'static,
P: Stream<Item = Bytes, Error = PayloadError> + 'static,
U: DeserializeOwned + 'static,
{
/// Create `JsonBody` for request.
pub fn new(req: &mut T) -> Self {
pub fn new(req: &HttpRequest, payload: &mut Payload<P>) -> Self {
// check content-type
let json = if let Ok(Some(mime)) = req.mime_type() {
mime.subtype() == mime::JSON || mime.suffix() == Some(mime::JSON)
@ -308,7 +306,7 @@ where
JsonBody {
limit: 262_144,
length: len,
stream: req.take_payload(),
stream: payload.take(),
fut: 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
T: HttpMessage,
T::Stream: Stream<Item = Bytes, Error = PayloadError> + 'static,
P: Stream<Item = Bytes, Error = PayloadError> + 'static,
U: DeserializeOwned + 'static,
{
type Item = U;
@ -410,7 +407,7 @@ mod tests {
#[test]
fn test_extract() {
let mut req = TestRequest::default()
let (req, mut pl) = TestRequest::default()
.header(
header::CONTENT_TYPE,
header::HeaderValue::from_static("application/json"),
@ -420,9 +417,9 @@ mod tests {
header::HeaderValue::from_static("16"),
)
.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.into_inner(),
@ -431,7 +428,7 @@ mod tests {
}
);
let mut req = TestRequest::default()
let (req, mut pl) = TestRequest::default()
.header(
header::CONTENT_TYPE,
header::HeaderValue::from_static("application/json"),
@ -442,12 +439,13 @@ mod tests {
)
.set_payload(Bytes::from_static(b"{\"name\": \"test\"}"))
.route_data(JsonConfig::default().limit(10))
.to_from();
let s = block_on(Json::<MyObject>::from_request(&mut req));
.to_http_parts();
let s = block_on(Json::<MyObject>::from_request(&req, &mut pl));
assert!(format!("{}", s.err().unwrap())
.contains("Json payload size is bigger than allowed."));
let mut req = TestRequest::default()
let (req, mut pl) = TestRequest::default()
.header(
header::CONTENT_TYPE,
header::HeaderValue::from_static("application/json"),
@ -462,27 +460,27 @@ mod tests {
.limit(10)
.error_handler(|_, _| JsonPayloadError::ContentType.into()),
)
.to_from();
let s = block_on(Json::<MyObject>::from_request(&mut req));
.to_http_parts();
let s = block_on(Json::<MyObject>::from_request(&req, &mut pl));
assert!(format!("{}", s.err().unwrap()).contains("Content type error"));
}
#[test]
fn test_json_body() {
let mut req = TestRequest::default().to_request();
let json = block_on(JsonBody::<_, MyObject>::new(&mut req));
let (req, mut pl) = TestRequest::default().to_http_parts();
let json = block_on(JsonBody::<_, MyObject>::new(&req, &mut pl));
assert!(json_eq(json.err().unwrap(), JsonPayloadError::ContentType));
let mut req = TestRequest::default()
let (req, mut pl) = TestRequest::default()
.header(
header::CONTENT_TYPE,
header::HeaderValue::from_static("application/text"),
)
.to_request();
let json = block_on(JsonBody::<_, MyObject>::new(&mut req));
.to_http_parts();
let json = block_on(JsonBody::<_, MyObject>::new(&req, &mut pl));
assert!(json_eq(json.err().unwrap(), JsonPayloadError::ContentType));
let mut req = TestRequest::default()
let (req, mut pl) = TestRequest::default()
.header(
header::CONTENT_TYPE,
header::HeaderValue::from_static("application/json"),
@ -491,12 +489,12 @@ mod tests {
header::CONTENT_LENGTH,
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));
let mut req = TestRequest::default()
let (req, mut pl) = TestRequest::default()
.header(
header::CONTENT_TYPE,
header::HeaderValue::from_static("application/json"),
@ -506,9 +504,9 @@ mod tests {
header::HeaderValue::from_static("16"),
)
.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!(
json.ok().unwrap(),
MyObject {

View File

@ -6,8 +6,8 @@ use actix_http::error::{Error, ErrorNotFound};
use actix_router::PathDeserializer;
use serde::de;
use crate::dev::Payload;
use crate::request::HttpRequest;
use crate::service::ServiceFromRequest;
use crate::FromRequest;
#[derive(PartialEq, Eq, PartialOrd, Ord)]
@ -66,15 +66,6 @@ impl<T> Path<T> {
pub fn into_inner(self) -> T {
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> {
@ -169,8 +160,10 @@ where
type Future = Result<Self, Error>;
#[inline]
fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future {
Self::extract(req.request()).map_err(ErrorNotFound)
fn from_request(req: &HttpRequest, _: &mut Payload<P>) -> Self::Future {
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() {
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());
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]
fn test_tuple_extract() {
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());
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).1, "user1");
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();
assert_eq!((res.0).0, "name");
@ -211,7 +209,7 @@ mod tests {
assert_eq!((res.1).0, "name");
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 mime::Mime;
use crate::dev;
use crate::extract::FromRequest;
use crate::http::header;
use crate::service::ServiceFromRequest;
use crate::request::HttpRequest;
/// Payload extractor returns request 's payload stream.
///
@ -92,8 +93,8 @@ where
type Future = Result<Payload, Error>;
#[inline]
fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future {
let pl = match req.take_payload() {
fn from_request(_: &HttpRequest, payload: &mut dev::Payload<P>) -> Self::Future {
let pl = match payload.take() {
crate::dev::Payload::Stream(s) => {
let pl: Box<dyn Stream<Item = Bytes, Error = PayloadError>> =
Box::new(s);
@ -141,7 +142,7 @@ where
Either<Box<Future<Item = Bytes, Error = Error>>, FutureResult<Bytes, Error>>;
#[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 cfg = if let Some(cfg) = req.route_data::<PayloadConfig>() {
cfg
@ -155,7 +156,9 @@ where
}
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>>;
#[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 cfg = if let Some(cfg) = req.route_data::<PayloadConfig>() {
cfg
@ -216,7 +219,7 @@ where
let limit = cfg.limit;
Either::A(Box::new(
HttpMessageBody::new(req)
HttpMessageBody::new(req, payload)
.limit(limit)
.from_err()
.and_then(move |body| {
@ -260,7 +263,7 @@ impl PayloadConfig {
self
}
fn check_mimetype<P>(&self, req: &ServiceFromRequest<P>) -> Result<(), Error> {
fn check_mimetype(&self, req: &HttpRequest) -> Result<(), Error> {
// check content-type
if let Some(ref mt) = self.mimetype {
match req.mime_type() {
@ -297,21 +300,20 @@ impl Default for PayloadConfig {
/// By default only 256Kb payload reads to a memory, then
/// `PayloadError::Overflow` get returned. Use `MessageBody::limit()`
/// method to change upper limit.
pub struct HttpMessageBody<T: HttpMessage> {
pub struct HttpMessageBody<P> {
limit: usize,
length: Option<usize>,
stream: actix_http::Payload<T::Stream>,
stream: dev::Payload<P>,
err: Option<PayloadError>,
fut: Option<Box<Future<Item = Bytes, Error = PayloadError>>>,
}
impl<T> HttpMessageBody<T>
impl<P> HttpMessageBody<P>
where
T: HttpMessage,
T::Stream: Stream<Item = Bytes, Error = PayloadError>,
P: Stream<Item = Bytes, Error = PayloadError>,
{
/// 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;
if let Some(l) = req.headers().get(&header::CONTENT_LENGTH) {
if let Ok(s) = l.to_str() {
@ -326,7 +328,7 @@ where
}
HttpMessageBody {
stream: req.take_payload(),
stream: payload.take(),
limit: 262_144,
length: len,
fut: None,
@ -342,7 +344,7 @@ where
fn err(e: PayloadError) -> Self {
HttpMessageBody {
stream: actix_http::Payload::None,
stream: dev::Payload::None,
limit: 262_144,
fut: None,
err: Some(e),
@ -351,10 +353,9 @@ where
}
}
impl<T> Future for HttpMessageBody<T>
impl<P> Future for HttpMessageBody<P>
where
T: HttpMessage,
T::Stream: Stream<Item = Bytes, Error = PayloadError> + 'static,
P: Stream<Item = Bytes, Error = PayloadError> + 'static,
{
type Item = Bytes;
type Error = PayloadError;
@ -403,7 +404,7 @@ mod tests {
#[test]
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);
assert!(cfg.check_mimetype(&req).is_err());
@ -411,62 +412,64 @@ mod tests {
header::CONTENT_TYPE,
"application/x-www-form-urlencoded",
)
.to_from();
.to_http_request();
assert!(cfg.check_mimetype(&req).is_err());
let req =
TestRequest::with_header(header::CONTENT_TYPE, "application/json").to_from();
let req = TestRequest::with_header(header::CONTENT_TYPE, "application/json")
.to_http_request();
assert!(cfg.check_mimetype(&req).is_ok());
}
#[test]
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"))
.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"));
}
#[test]
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"))
.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");
}
#[test]
fn test_message_body() {
let mut req =
TestRequest::with_header(header::CONTENT_LENGTH, "xxxx").to_request();
let res = block_on(HttpMessageBody::new(&mut req));
let (req, mut pl) = TestRequest::with_header(header::CONTENT_LENGTH, "xxxx")
.to_srv_request()
.into_parts();
let res = block_on(HttpMessageBody::new(&req, &mut pl));
match res.err().unwrap() {
PayloadError::UnknownLength => (),
_ => unreachable!("error"),
}
let mut req =
TestRequest::with_header(header::CONTENT_LENGTH, "1000000").to_request();
let res = block_on(HttpMessageBody::new(&mut req));
let (req, mut pl) = TestRequest::with_header(header::CONTENT_LENGTH, "1000000")
.to_srv_request()
.into_parts();
let res = block_on(HttpMessageBody::new(&req, &mut pl));
match res.err().unwrap() {
PayloadError::Overflow => (),
_ => unreachable!("error"),
}
let mut req = TestRequest::default()
let (req, mut pl) = TestRequest::default()
.set_payload(Bytes::from_static(b"test"))
.to_request();
let res = block_on(HttpMessageBody::new(&mut req));
.to_http_parts();
let res = block_on(HttpMessageBody::new(&req, &mut pl));
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"))
.to_request();
let res = block_on(HttpMessageBody::new(&mut req).limit(5));
.to_http_parts();
let res = block_on(HttpMessageBody::new(&req, &mut pl).limit(5));
match res.err().unwrap() {
PayloadError::Overflow => (),
_ => unreachable!("error"),

View File

@ -6,8 +6,9 @@ use actix_http::error::Error;
use serde::de;
use serde_urlencoded;
use crate::dev::Payload;
use crate::extract::FromRequest;
use crate::service::ServiceFromRequest;
use crate::request::HttpRequest;
#[derive(PartialEq, Eq, PartialOrd, Ord)]
/// Extract typed information from from the request's query.
@ -118,8 +119,8 @@ where
type Future = Result<Self, Error>;
#[inline]
fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future {
serde_urlencoded::from_str::<T>(req.request().query_string())
fn from_request(req: &HttpRequest, _: &mut Payload<P>) -> Self::Future {
serde_urlencoded::from_str::<T>(req.query_string())
.map(|val| Ok(Query(val)))
.unwrap_or_else(|e| Err(e.into()))
}