tower_async_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::{Limited, LengthLimitError, Full};
28//! use tower_async::{Service, ServiceExt, ServiceBuilder};
29//! use tower_async_http::limit::RequestBodyLimitLayer;
30//!
31//! # #[tokio::main]
32//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
33//! async fn handle(req: Request<Limited<Full<Bytes>>>) -> Result<Response<Full<Bytes>>, Infallible> {
34//!     panic!("This will not be hit")
35//! }
36//!
37//! let mut svc = ServiceBuilder::new()
38//!     // Limit incoming requests to 4096 bytes.
39//!     .layer(RequestBodyLimitLayer::new(4096))
40//!     .service_fn(handle);
41//!
42//! // Call the service with a header that indicates the body is too large.
43//! let mut request = Request::builder()
44//!     .header(CONTENT_LENGTH, HeaderValue::from_static("5000"))
45//!     .body(Full::<Bytes>::default())
46//!     .unwrap();
47//!
48//! let response = svc.call(request).await?;
49//!
50//! assert_eq!(response.status(), StatusCode::PAYLOAD_TOO_LARGE);
51//! #
52//! # Ok(())
53//! # }
54//! ```
55//!
56//! ## Limiting without known `Content-Length`
57//!
58//! If a `Content-Length` header is not present, then the body will be read
59//! until the configured limit has been reached. If the payload is larger than
60//! the limit, the [`http_body_util::Limited`] body will return an error. This
61//! error can be inspected to determine if it is a [`http_body_util::LengthLimitError`]
62//! and return an appropriate response in such case.
63//!
64//! Note that no error will be generated if the body is never read. Similarly,
65//! if the body _would be_ to large, but is never consumed beyond the length
66//! limit, then no error is generated, and handling of the remaining incoming
67//! data stream is left to the server implementation as described above.
68//!
69//! ```rust
70//! # use bytes::Bytes;
71//! # use std::convert::Infallible;
72//! # use http::{Request, Response, StatusCode};
73//! # use http_body_util::{Limited, LengthLimitError, Full, BodyExt};
74//! # use tower_async::{Service, ServiceExt, ServiceBuilder, BoxError};
75//! # use tower_async_http::limit::RequestBodyLimitLayer;
76//! #
77//! # type Body = Full<Bytes>;
78//! #
79//! # #[tokio::main]
80//! # async fn main() -> Result<(), BoxError> {
81//! async fn handle(req: Request<Limited<Body>>) -> Result<Response<Body>, BoxError> {
82//!     let data = match req.into_body().collect().await {
83//!         Ok(data) => data,
84//!         Err(err) => {
85//!             if let Some(_) = err.downcast_ref::<LengthLimitError>() {
86//!                 let mut resp = Response::new(Body::default());
87//!                 *resp.status_mut() = StatusCode::PAYLOAD_TOO_LARGE;
88//!                 return Ok(resp);
89//!             } else {
90//!                 return Err(err);
91//!             }
92//!         }
93//!     };
94//!
95//!     Ok(Response::new(Body::default()))
96//! }
97//!
98//! let mut svc = ServiceBuilder::new()
99//!     // Limit incoming requests to 4096 bytes.
100//!     .layer(RequestBodyLimitLayer::new(4096))
101//!     .service_fn(handle);
102//!
103//! // Call the service.
104//! let request = Request::new(Body::default());
105//!
106//! let response = svc.call(request).await?;
107//!
108//! assert_eq!(response.status(), StatusCode::OK);
109//!
110//! // Call the service with a body that is too large.
111//! let request = Request::new(Body::from(Bytes::from(vec![0u8; 4097])));
112//!
113//! let response = svc.call(request).await?;
114//!
115//! assert_eq!(response.status(), StatusCode::PAYLOAD_TOO_LARGE);
116//! #
117//! # Ok(())
118//! # }
119//! ```
120//!
121//! ## Limiting without `Content-Length`
122//!
123//! If enforcement of body size limits is desired without preemptively
124//! handling requests with a `Content-Length` header indicating an over-sized
125//! request, consider using [`MapRequestBody`] to wrap the request body with
126//! [`http_body_util::Limited`] and checking for [`http_body_util::LengthLimitError`]
127//! like in the previous example.
128//!
129//! [`MapRequestBody`]: crate::map_request_body
130//! [hyper]: https://crates.io/crates/hyper
131
132mod body;
133mod layer;
134mod service;
135
136pub use body::ResponseBody;
137pub use layer::RequestBodyLimitLayer;
138pub use service::RequestBodyLimit;