Adjust JSON limit to 2MB and report on sizes

This commit is contained in:
peter-formlogic 2021-04-14 17:12:03 +09:30
parent ff65f1d006
commit 6189caa521
No known key found for this signature in database
GPG Key ID: CE3C608698F6E66B
2 changed files with 30 additions and 16 deletions

View File

@ -86,9 +86,13 @@ impl ResponseError for UrlencodedError {
#[derive(Debug, Display, Error)] #[derive(Debug, Display, Error)]
#[non_exhaustive] #[non_exhaustive]
pub enum JsonPayloadError { pub enum JsonPayloadError {
/// Payload size is bigger than allowed. (default: 32kB) /// Payload size is bigger than allowed. (default: 2MB)
#[display(fmt = "Json payload size is bigger than allowed")] #[display(
Overflow, fmt = "JSON payload ({} bytes) is larger than allowed (limit: {} bytes).",
size,
limit
)]
Overflow { size: usize, limit: usize },
/// Content type error /// Content type error
#[display(fmt = "Content type error")] #[display(fmt = "Content type error")]
@ -116,7 +120,7 @@ impl From<PayloadError> for JsonPayloadError {
impl ResponseError for JsonPayloadError { impl ResponseError for JsonPayloadError {
fn status_code(&self) -> StatusCode { fn status_code(&self) -> StatusCode {
match self { match self {
Self::Overflow => StatusCode::PAYLOAD_TOO_LARGE, Self::Overflow { size: _, limit: _ } => StatusCode::PAYLOAD_TOO_LARGE,
Self::Serialize(_) => StatusCode::INTERNAL_SERVER_ERROR, Self::Serialize(_) => StatusCode::INTERNAL_SERVER_ERROR,
Self::Payload(err) => err.status_code(), Self::Payload(err) => err.status_code(),
_ => StatusCode::BAD_REQUEST, _ => StatusCode::BAD_REQUEST,
@ -203,7 +207,7 @@ mod tests {
#[test] #[test]
fn test_json_payload_error() { fn test_json_payload_error() {
let resp = JsonPayloadError::Overflow.error_response(); let resp = JsonPayloadError::Overflow{size: 0, limit: 0}.error_response();
assert_eq!(resp.status(), StatusCode::PAYLOAD_TOO_LARGE); assert_eq!(resp.status(), StatusCode::PAYLOAD_TOO_LARGE);
let resp = JsonPayloadError::ContentType.error_response(); let resp = JsonPayloadError::ContentType.error_response();
assert_eq!(resp.status(), StatusCode::BAD_REQUEST); assert_eq!(resp.status(), StatusCode::BAD_REQUEST);

View File

@ -240,7 +240,7 @@ pub struct JsonConfig {
} }
impl JsonConfig { impl JsonConfig {
/// Set maximum accepted payload size. By default this limit is 32kB. /// Set maximum accepted payload size. By default this limit is 2MB.
pub fn limit(mut self, limit: usize) -> Self { pub fn limit(mut self, limit: usize) -> Self {
self.limit = limit; self.limit = limit;
self self
@ -273,9 +273,11 @@ impl JsonConfig {
} }
} }
const DEFAULT_LIMIT: usize = 2_097_152; // 2 mb
/// Allow shared refs used as default. /// Allow shared refs used as default.
const DEFAULT_CONFIG: JsonConfig = JsonConfig { const DEFAULT_CONFIG: JsonConfig = JsonConfig {
limit: 32_768, // 2^15 bytes, (~32kB) limit: DEFAULT_LIMIT,
err_handler: None, err_handler: None,
content_type: None, content_type: None,
}; };
@ -349,7 +351,7 @@ where
let payload = payload.take(); let payload = payload.take();
JsonBody::Body { JsonBody::Body {
limit: 32_768, limit: DEFAULT_LIMIT,
length, length,
payload, payload,
buf: BytesMut::with_capacity(8192), buf: BytesMut::with_capacity(8192),
@ -357,7 +359,7 @@ where
} }
} }
/// Set maximum accepted payload size. The default limit is 32kB. /// Set maximum accepted payload size. The default limit is 2MB.
pub fn limit(self, limit: usize) -> Self { pub fn limit(self, limit: usize) -> Self {
match self { match self {
JsonBody::Body { JsonBody::Body {
@ -368,7 +370,10 @@ where
} => { } => {
if let Some(len) = length { if let Some(len) = length {
if len > limit { if len > limit {
return JsonBody::Error(Some(JsonPayloadError::Overflow)); return JsonBody::Error(Some(JsonPayloadError::Overflow {
size: len,
limit,
}));
} }
} }
@ -399,14 +404,19 @@ where
limit, limit,
buf, buf,
payload, payload,
length,
.. ..
} => loop { } => loop {
let res = ready!(Pin::new(&mut *payload).poll_next(cx)); let res = ready!(Pin::new(&mut *payload).poll_next(cx));
match res { match res {
Some(chunk) => { Some(chunk) => {
let chunk = chunk?; let chunk = chunk?;
if (buf.len() + chunk.len()) > *limit { let buf_len = buf.len() + chunk.len();
return Poll::Ready(Err(JsonPayloadError::Overflow)); if buf_len > *limit {
return Poll::Ready(Err(JsonPayloadError::Overflow {
size: length.unwrap_or(buf_len),
limit: *limit,
}));
} else { } else {
buf.extend_from_slice(&chunk); buf.extend_from_slice(&chunk);
} }
@ -445,7 +455,7 @@ mod tests {
fn json_eq(err: JsonPayloadError, other: JsonPayloadError) -> bool { fn json_eq(err: JsonPayloadError, other: JsonPayloadError) -> bool {
match err { match err {
JsonPayloadError::Overflow => matches!(other, JsonPayloadError::Overflow), JsonPayloadError::Overflow { .. } => matches!(other, JsonPayloadError::Overflow { .. }),
JsonPayloadError::ContentType => matches!(other, JsonPayloadError::ContentType), JsonPayloadError::ContentType => matches!(other, JsonPayloadError::ContentType),
_ => false, _ => false,
} }
@ -538,7 +548,7 @@ mod tests {
let s = Json::<MyObject>::from_request(&req, &mut pl).await; let s = Json::<MyObject>::from_request(&req, &mut pl).await;
assert!(format!("{}", s.err().unwrap()) assert!(format!("{}", s.err().unwrap())
.contains("Json payload size is bigger than allowed")); .contains("JSON payload (16 bytes) is larger than allowed (limit: 10 bytes)."));
let (req, mut pl) = TestRequest::default() let (req, mut pl) = TestRequest::default()
.insert_header(( .insert_header((
@ -589,7 +599,7 @@ mod tests {
let json = JsonBody::<MyObject>::new(&req, &mut pl, None) let json = JsonBody::<MyObject>::new(&req, &mut pl, None)
.limit(100) .limit(100)
.await; .await;
assert!(json_eq(json.err().unwrap(), JsonPayloadError::Overflow)); assert!(json_eq(json.err().unwrap(), JsonPayloadError::Overflow { size: 10000, limit: 100 }));
let (req, mut pl) = TestRequest::default() let (req, mut pl) = TestRequest::default()
.insert_header(( .insert_header((
@ -686,6 +696,6 @@ mod tests {
assert!(s.is_err()); assert!(s.is_err());
let err_str = s.err().unwrap().to_string(); let err_str = s.err().unwrap().to_string();
assert!(err_str.contains("Json payload size is bigger than allowed")); assert!(err_str.contains("JSON payload (16 bytes) is larger than allowed (limit: 10 bytes)."));
} }
} }