Skip to main content

mini_serve/
body.rs

1use hyper::body::Incoming;
2use hyper::Request;
3use http_body_util::{BodyExt, LengthLimitError, Limited};
4use serde::de::DeserializeOwned;
5
6use crate::error::ServeError;
7
8/// Default maximum request body size: 2 MiB.
9pub const DEFAULT_MAX_BODY_SIZE: usize = 2_097_152;
10
11/// Maximum body size limit for a request.
12///
13/// Extracted from the request extensions set by the app.
14/// Prevents denial-of-service attacks from clients sending arbitrarily large bodies.
15#[derive(Clone, Copy, Debug)]
16pub struct MaxBodySize(pub usize);
17
18/// Extract a JSON-deserialized body from the request.
19///
20/// Returns an HTTP 400 if the body is not valid JSON, or 413 if it exceeds
21/// the configured size limit.
22pub async fn json_body<T: DeserializeOwned>(req: Request<Incoming>) -> Result<T, ServeError> {
23	let (parts, body) = req.into_parts();
24	let max = parts
25		.extensions
26		.get::<MaxBodySize>()
27		.map(|m| m.0)
28		.unwrap_or(DEFAULT_MAX_BODY_SIZE);
29
30	if let Some(content_length) = parts.headers.get("content-length") {
31		if let Ok(s) = content_length.to_str() {
32			if let Ok(len) = s.parse::<usize>() {
33				if len > max {
34					return Err(ServeError::new(413, "request body too large"));
35				}
36			}
37		}
38	}
39
40	let limited = Limited::new(body, max);
41	let collected = limited
42		.collect()
43		.await
44		.map_err(|e| {
45			if e.downcast_ref::<LengthLimitError>().is_some() {
46				ServeError::new(413, "request body too large")
47			} else {
48				ServeError::new(400, "failed to read request body")
49			}
50		})?;
51	let bytes = collected.to_bytes();
52	serde_json::from_slice(&bytes)
53		.map_err(|_| ServeError::new(400, "invalid json body"))
54}