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