1
0
mirror of https://github.com/actix/actix-extras.git synced 2025-06-27 10:39:03 +02: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

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