tower_http/limit/
mod.rs

1//! Middleware for limiting request bodies.
2//!
3//! This layer will also intercept requests with a `Content-Length` header
4//! larger than the allowable limit and return an immediate error response
5//! before reading any of the body.
6//!
7//! Note that payload length errors can be used by adversaries in an attempt
8//! to smuggle requests. When an incoming stream is dropped due to an
9//! over-sized payload, servers should close the connection or resynchronize
10//! by optimistically consuming some data in an attempt to reach the end of
11//! the current HTTP frame. If the incoming stream cannot be resynchronized,
12//! then the connection should be closed. If you're using [hyper] this is
13//! automatically handled for you.
14//!
15//! # Examples
16//!
17//! ## Limiting based on `Content-Length`
18//!
19//! If a `Content-Length` header is present and indicates a payload that is
20//! larger than the acceptable limit, then the underlying service will not
21//! be called and a `413 Payload Too Large` response will be generated.
22//!
23//! ```rust
24//! use bytes::Bytes;
25//! use std::convert::Infallible;
26//! use http::{Request, Response, StatusCode, HeaderValue, header::CONTENT_LENGTH};
27//! use http_body_util::{LengthLimitError};
28//! use tower::{Service, ServiceExt, ServiceBuilder};
29//! use tower_http::{body::Limited, limit::RequestBodyLimitLayer};
30//! use http_body_util::Full;
31//!
32//! # #[tokio::main]
33//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
34//! async fn handle(req: Request<Limited<Full<Bytes>>>) -> Result<Response<Full<Bytes>>, Infallible> {
35//!     panic!("This should not be hit")
36//! }
37//!
38//! let mut svc = ServiceBuilder::new()
39//!     // Limit incoming requests to 4096 bytes.
40//!     .layer(RequestBodyLimitLayer::new(4096))
41//!     .service_fn(handle);
42//!
43//! // Call the service with a header that indicates the body is too large.
44//! let mut request = Request::builder()
45//!     .header(CONTENT_LENGTH, HeaderValue::from_static("5000"))
46//!     .body(Full::<Bytes>::default())
47//!     .unwrap();
48//!
49//! // let response = svc.ready().await?.call(request).await?;
50//! let response = svc.call(request).await?;
51//!
52//! assert_eq!(response.status(), StatusCode::PAYLOAD_TOO_LARGE);
53//! #
54//! # Ok(())
55//! # }
56//! ```
57//!
58//! ## Limiting without known `Content-Length`
59//!
60//! If a `Content-Length` header is not present, then the body will be read
61//! until the configured limit has been reached. If the payload is larger than
62//! the limit, the [`http_body_util::Limited`] body will return an error. This
63//! error can be inspected to determine if it is a [`http_body_util::LengthLimitError`]
64//! and return an appropriate response in such case.
65//!
66//! Note that no error will be generated if the body is never read. Similarly,
67//! if the body _would be_ to large, but is never consumed beyond the length
68//! limit, then no error is generated, and handling of the remaining incoming
69//! data stream is left to the server implementation as described above.
70//!
71//! ```rust
72//! # use bytes::Bytes;
73//! # use std::convert::Infallible;
74//! # use http::{Request, Response, StatusCode};
75//! # use http_body_util::LengthLimitError;
76//! # use tower::{Service, ServiceExt, ServiceBuilder, BoxError};
77//! # use tower_http::{body::Limited, limit::RequestBodyLimitLayer};
78//! # use http_body_util::Full;
79//! # use http_body_util::BodyExt;
80//! #
81//! # #[tokio::main]
82//! # async fn main() -> Result<(), BoxError> {
83//! async fn handle(req: Request<Limited<Full<Bytes>>>) -> Result<Response<Full<Bytes>>, BoxError> {
84//!     let data = match req.into_body().collect().await {
85//!         Ok(collected) => collected.to_bytes(),
86//!         Err(err) => {
87//!             if let Some(_) = err.downcast_ref::<LengthLimitError>() {
88//!                 let mut resp = Response::new(Full::default());
89//!                 *resp.status_mut() = StatusCode::PAYLOAD_TOO_LARGE;
90//!                 return Ok(resp);
91//!             } else {
92//!                 return Err(err);
93//!             }
94//!         }
95//!     };
96//!
97//!     Ok(Response::new(Full::default()))
98//! }
99//!
100//! let mut svc = ServiceBuilder::new()
101//!     // Limit incoming requests to 4096 bytes.
102//!     .layer(RequestBodyLimitLayer::new(4096))
103//!     .service_fn(handle);
104//!
105//! // Call the service.
106//! let request = Request::new(Full::<Bytes>::default());
107//!
108//! let response = svc.ready().await?.call(request).await?;
109//!
110//! assert_eq!(response.status(), StatusCode::OK);
111//!
112//! // Call the service with a body that is too large.
113//! let request = Request::new(Full::<Bytes>::from(Bytes::from(vec![0u8; 4097])));
114//!
115//! let response = svc.ready().await?.call(request).await?;
116//!
117//! assert_eq!(response.status(), StatusCode::PAYLOAD_TOO_LARGE);
118//! #
119//! # Ok(())
120//! # }
121//! ```
122//!
123//! ## Limiting without `Content-Length`
124//!
125//! If enforcement of body size limits is desired without preemptively
126//! handling requests with a `Content-Length` header indicating an over-sized
127//! request, consider using [`MapRequestBody`] to wrap the request body with
128//! [`http_body_util::Limited`] and checking for [`http_body_util::LengthLimitError`]
129//! like in the previous example.
130//!
131//! [`MapRequestBody`]: crate::map_request_body
132//! [hyper]: https://crates.io/crates/hyper
133
134mod body;
135mod future;
136mod layer;
137mod service;
138
139pub use body::ResponseBody;
140pub use future::ResponseFuture;
141pub use layer::RequestBodyLimitLayer;
142pub use service::RequestBodyLimit;