mirror of
https://github.com/fafhrd91/actix-web
synced 2024-11-23 16:21:06 +01:00
refactor FromRequest trait
This commit is contained in:
parent
3c650ca194
commit
75b213a6f0
@ -14,6 +14,8 @@
|
||||
|
||||
### Changed
|
||||
|
||||
* `FromRequest` trait refactoring
|
||||
|
||||
* Move multipart support to actix-multipart crate
|
||||
|
||||
|
||||
|
@ -10,8 +10,8 @@ use std::{cmp, io};
|
||||
use actix_service::boxed::{self, BoxedNewService, BoxedService};
|
||||
use actix_service::{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())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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()))
|
||||
}
|
||||
}
|
||||
|
@ -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()));
|
||||
|
||||
|
@ -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 {
|
||||
|
110
src/extract.rs
110
src/extract.rs
@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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)))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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()))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
|
10
src/route.rs
10
src/route.rs
@ -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>;
|
||||
|
@ -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>,
|
||||
|
33
src/test.rs
33
src/test.rs
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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"),
|
||||
|
@ -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()))
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user