mirror of
https://github.com/fafhrd91/actix-web
synced 2024-11-27 17:52:56 +01:00
extract more config types from Data<T> as well (#1641)
This commit is contained in:
parent
01cbef700f
commit
4e321595bc
@ -3,11 +3,16 @@
|
|||||||
## Unreleased - 2020-xx-xx
|
## Unreleased - 2020-xx-xx
|
||||||
### Added
|
### Added
|
||||||
* `middleware::NormalizePath` now has configurable behaviour for either always having a trailing
|
* `middleware::NormalizePath` now has configurable behaviour for either always having a trailing
|
||||||
slash, or as the new addition, always trimming trailing slashes.
|
slash, or as the new addition, always trimming trailing slashes. [#1639]
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
* Update actix-codec and actix-utils dependencies.
|
* Update actix-codec and actix-utils dependencies. [#1634]
|
||||||
|
* `FormConfig` and `JsonConfig` configurations are now also considered when set
|
||||||
|
using `App::data`. [#1641]
|
||||||
|
|
||||||
|
[#1639]: https://github.com/actix/actix-web/pull/1639
|
||||||
|
[#1641]: https://github.com/actix/actix-web/pull/1641
|
||||||
|
[#1634]: https://github.com/actix/actix-web/pull/1634
|
||||||
|
|
||||||
## 3.0.0-beta.3 - 2020-08-17
|
## 3.0.0-beta.3 - 2020-08-17
|
||||||
### Changed
|
### Changed
|
||||||
|
@ -23,7 +23,7 @@ use crate::http::{
|
|||||||
StatusCode,
|
StatusCode,
|
||||||
};
|
};
|
||||||
use crate::request::HttpRequest;
|
use crate::request::HttpRequest;
|
||||||
use crate::responder::Responder;
|
use crate::{responder::Responder, web};
|
||||||
|
|
||||||
/// Form data helper (`application/x-www-form-urlencoded`)
|
/// Form data helper (`application/x-www-form-urlencoded`)
|
||||||
///
|
///
|
||||||
@ -121,8 +121,12 @@ where
|
|||||||
fn from_request(req: &HttpRequest, payload: &mut Payload) -> Self::Future {
|
fn from_request(req: &HttpRequest, payload: &mut Payload) -> Self::Future {
|
||||||
let req2 = req.clone();
|
let req2 = req.clone();
|
||||||
let (limit, err) = req
|
let (limit, err) = req
|
||||||
.app_data::<FormConfig>()
|
.app_data::<Self::Config>()
|
||||||
.map(|c| (c.limit, c.ehandler.clone()))
|
.or_else(|| {
|
||||||
|
req.app_data::<web::Data<Self::Config>>()
|
||||||
|
.map(|d| d.as_ref())
|
||||||
|
})
|
||||||
|
.map(|c| (c.limit, c.err_handler.clone()))
|
||||||
.unwrap_or((16384, None));
|
.unwrap_or((16384, None));
|
||||||
|
|
||||||
UrlEncoded::new(req, payload)
|
UrlEncoded::new(req, payload)
|
||||||
@ -200,7 +204,7 @@ impl<T: Serialize> Responder for Form<T> {
|
|||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct FormConfig {
|
pub struct FormConfig {
|
||||||
limit: usize,
|
limit: usize,
|
||||||
ehandler: Option<Rc<dyn Fn(UrlencodedError, &HttpRequest) -> Error>>,
|
err_handler: Option<Rc<dyn Fn(UrlencodedError, &HttpRequest) -> Error>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FormConfig {
|
impl FormConfig {
|
||||||
@ -215,7 +219,7 @@ impl FormConfig {
|
|||||||
where
|
where
|
||||||
F: Fn(UrlencodedError, &HttpRequest) -> Error + 'static,
|
F: Fn(UrlencodedError, &HttpRequest) -> Error + 'static,
|
||||||
{
|
{
|
||||||
self.ehandler = Some(Rc::new(f));
|
self.err_handler = Some(Rc::new(f));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -223,8 +227,8 @@ impl FormConfig {
|
|||||||
impl Default for FormConfig {
|
impl Default for FormConfig {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
FormConfig {
|
FormConfig {
|
||||||
limit: 16384,
|
limit: 16_384, // 2^14 bytes (~16kB)
|
||||||
ehandler: None,
|
err_handler: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -378,7 +382,7 @@ mod tests {
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::http::header::{HeaderValue, CONTENT_TYPE};
|
use crate::http::header::{HeaderValue, CONTENT_LENGTH, CONTENT_TYPE};
|
||||||
use crate::test::TestRequest;
|
use crate::test::TestRequest;
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize, Debug, PartialEq)]
|
#[derive(Deserialize, Serialize, Debug, PartialEq)]
|
||||||
@ -499,4 +503,22 @@ mod tests {
|
|||||||
use crate::responder::tests::BodyTest;
|
use crate::responder::tests::BodyTest;
|
||||||
assert_eq!(resp.body().bin_ref(), b"hello=world&counter=123");
|
assert_eq!(resp.body().bin_ref(), b"hello=world&counter=123");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[actix_rt::test]
|
||||||
|
async fn test_with_config_in_data_wrapper() {
|
||||||
|
let ctype = HeaderValue::from_static("application/x-www-form-urlencoded");
|
||||||
|
|
||||||
|
let (req, mut pl) = TestRequest::default()
|
||||||
|
.header(CONTENT_TYPE, ctype)
|
||||||
|
.header(CONTENT_LENGTH, HeaderValue::from_static("20"))
|
||||||
|
.set_payload(Bytes::from_static(b"hello=test&counter=4"))
|
||||||
|
.app_data(web::Data::new(FormConfig::default().limit(10)))
|
||||||
|
.to_http_parts();
|
||||||
|
|
||||||
|
let s = Form::<Info>::from_request(&req, &mut pl).await;
|
||||||
|
assert!(s.is_err());
|
||||||
|
|
||||||
|
let err_str = s.err().unwrap().to_string();
|
||||||
|
assert!(err_str.contains("Urlencoded payload size is bigger"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ use crate::dev::Decompress;
|
|||||||
use crate::error::{Error, JsonPayloadError};
|
use crate::error::{Error, JsonPayloadError};
|
||||||
use crate::extract::FromRequest;
|
use crate::extract::FromRequest;
|
||||||
use crate::request::HttpRequest;
|
use crate::request::HttpRequest;
|
||||||
use crate::responder::Responder;
|
use crate::{responder::Responder, web};
|
||||||
|
|
||||||
/// Json helper
|
/// Json helper
|
||||||
///
|
///
|
||||||
@ -179,10 +179,11 @@ where
|
|||||||
#[inline]
|
#[inline]
|
||||||
fn from_request(req: &HttpRequest, payload: &mut Payload) -> Self::Future {
|
fn from_request(req: &HttpRequest, payload: &mut Payload) -> Self::Future {
|
||||||
let req2 = req.clone();
|
let req2 = req.clone();
|
||||||
let (limit, err, ctype) = req
|
let config = JsonConfig::from_req(req);
|
||||||
.app_data::<Self::Config>()
|
|
||||||
.map(|c| (c.limit, c.ehandler.clone(), c.content_type.clone()))
|
let limit = config.limit;
|
||||||
.unwrap_or((32768, None, None));
|
let ctype = config.content_type.clone();
|
||||||
|
let err_handler = config.err_handler.clone();
|
||||||
|
|
||||||
JsonBody::new(req, payload, ctype)
|
JsonBody::new(req, payload, ctype)
|
||||||
.limit(limit)
|
.limit(limit)
|
||||||
@ -193,7 +194,8 @@ where
|
|||||||
Request path: {}",
|
Request path: {}",
|
||||||
req2.path()
|
req2.path()
|
||||||
);
|
);
|
||||||
if let Some(err) = err {
|
|
||||||
|
if let Some(err) = err_handler {
|
||||||
Err((*err)(e, &req2))
|
Err((*err)(e, &req2))
|
||||||
} else {
|
} else {
|
||||||
Err(e.into())
|
Err(e.into())
|
||||||
@ -255,7 +257,8 @@ where
|
|||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct JsonConfig {
|
pub struct JsonConfig {
|
||||||
limit: usize,
|
limit: usize,
|
||||||
ehandler: Option<Arc<dyn Fn(JsonPayloadError, &HttpRequest) -> Error + Send + Sync>>,
|
err_handler:
|
||||||
|
Option<Arc<dyn Fn(JsonPayloadError, &HttpRequest) -> Error + Send + Sync>>,
|
||||||
content_type: Option<Arc<dyn Fn(mime::Mime) -> bool + Send + Sync>>,
|
content_type: Option<Arc<dyn Fn(mime::Mime) -> bool + Send + Sync>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -271,7 +274,7 @@ impl JsonConfig {
|
|||||||
where
|
where
|
||||||
F: Fn(JsonPayloadError, &HttpRequest) -> Error + Send + Sync + 'static,
|
F: Fn(JsonPayloadError, &HttpRequest) -> Error + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
self.ehandler = Some(Arc::new(f));
|
self.err_handler = Some(Arc::new(f));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -283,15 +286,26 @@ impl JsonConfig {
|
|||||||
self.content_type = Some(Arc::new(predicate));
|
self.content_type = Some(Arc::new(predicate));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Extract payload config from app data. Check both `T` and `Data<T>`, in that order, and fall
|
||||||
|
/// back to the default payload config.
|
||||||
|
fn from_req(req: &HttpRequest) -> &Self {
|
||||||
|
req.app_data::<Self>()
|
||||||
|
.or_else(|| req.app_data::<web::Data<Self>>().map(|d| d.as_ref()))
|
||||||
|
.unwrap_or_else(|| &DEFAULT_CONFIG)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Allow shared refs to default.
|
||||||
|
const DEFAULT_CONFIG: JsonConfig = JsonConfig {
|
||||||
|
limit: 32_768, // 2^15 bytes, (~32kB)
|
||||||
|
err_handler: None,
|
||||||
|
content_type: None,
|
||||||
|
};
|
||||||
|
|
||||||
impl Default for JsonConfig {
|
impl Default for JsonConfig {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
JsonConfig {
|
DEFAULT_CONFIG.clone()
|
||||||
limit: 32768,
|
|
||||||
ehandler: None,
|
|
||||||
content_type: None,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -422,7 +436,7 @@ mod tests {
|
|||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::error::InternalError;
|
use crate::error::InternalError;
|
||||||
use crate::http::header;
|
use crate::http::header::{self, HeaderValue, CONTENT_LENGTH, CONTENT_TYPE};
|
||||||
use crate::test::{load_stream, TestRequest};
|
use crate::test::{load_stream, TestRequest};
|
||||||
use crate::HttpResponse;
|
use crate::HttpResponse;
|
||||||
|
|
||||||
@ -659,4 +673,20 @@ mod tests {
|
|||||||
let s = Json::<MyObject>::from_request(&req, &mut pl).await;
|
let s = Json::<MyObject>::from_request(&req, &mut pl).await;
|
||||||
assert!(s.is_err())
|
assert!(s.is_err())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[actix_rt::test]
|
||||||
|
async fn test_with_config_in_data_wrapper() {
|
||||||
|
let (req, mut pl) = TestRequest::default()
|
||||||
|
.header(CONTENT_TYPE, HeaderValue::from_static("application/json"))
|
||||||
|
.header(CONTENT_LENGTH, HeaderValue::from_static("16"))
|
||||||
|
.set_payload(Bytes::from_static(b"{\"name\": \"test\"}"))
|
||||||
|
.app_data(web::Data::new(JsonConfig::default().limit(10)))
|
||||||
|
.to_http_parts();
|
||||||
|
|
||||||
|
let s = Json::<MyObject>::from_request(&req, &mut pl).await;
|
||||||
|
assert!(s.is_err());
|
||||||
|
|
||||||
|
let err_str = s.err().unwrap().to_string();
|
||||||
|
assert!(err_str.contains("Json payload size is bigger than allowed"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -279,27 +279,24 @@ impl PayloadConfig {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Allow payload config extraction from app data checking both `T` and `Data<T>`, in that
|
/// Extract payload config from app data. Check both `T` and `Data<T>`, in that order, and fall
|
||||||
/// order, and falling back to the default payload config.
|
/// back to the default payload config.
|
||||||
fn from_req(req: &HttpRequest) -> &PayloadConfig {
|
fn from_req(req: &HttpRequest) -> &Self {
|
||||||
req.app_data::<PayloadConfig>()
|
req.app_data::<Self>()
|
||||||
.or_else(|| {
|
.or_else(|| req.app_data::<web::Data<Self>>().map(|d| d.as_ref()))
|
||||||
req.app_data::<web::Data<PayloadConfig>>()
|
.unwrap_or_else(|| &DEFAULT_CONFIG)
|
||||||
.map(|d| d.as_ref())
|
|
||||||
})
|
|
||||||
.unwrap_or_else(|| &DEFAULT_PAYLOAD_CONFIG)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allow shared refs to default.
|
// Allow shared refs to default.
|
||||||
static DEFAULT_PAYLOAD_CONFIG: PayloadConfig = PayloadConfig {
|
const DEFAULT_CONFIG: PayloadConfig = PayloadConfig {
|
||||||
limit: 262_144, // 2^18 bytes (~256kB)
|
limit: 262_144, // 2^18 bytes (~256kB)
|
||||||
mimetype: None,
|
mimetype: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
impl Default for PayloadConfig {
|
impl Default for PayloadConfig {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
DEFAULT_PAYLOAD_CONFIG.clone()
|
DEFAULT_CONFIG.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user