rama_http/layer/timeout/mod.rs
1//! Middleware that applies a timeout to requests.
2//!
3//! If the request does not complete within the specified timeout, it will be aborted and a
4//! response with an empty body and a custom status code will be returned.
5//!
6//! # Differences from `rama_core::service::layer::Timeout`
7//!
8//! The generic [`Timeout`] middleware uses an error to signal timeout, i.e.
9//! it changes the error type to [`BoxError`](rama_core::error::BoxError). For HTTP services that is rarely
10//! what you want as returning errors will terminate the connection without sending a response.
11//!
12//! This middleware won't change the error type and instead returns a response with an empty body
13//! and the specified status code. That means if your service's error type is [`Infallible`], it will
14//! still be [`Infallible`] after applying this middleware.
15//!
16//! # Body timeouts
17//!
18//! Two body timeout wrappers are available for limiting how long a request or response body
19//! transfer can take:
20//!
21//! - [`TimeoutBody`] resets its deadline each time a frame is received. Use this to detect
22//! idle connections where no data flows for a period of time.
23//! - [`DeadlineBody`] starts a single timer at construction and never resets it. Use
24//! this to cap the total wall-clock time spent transferring a body, regardless of how
25//! frequently data arrives.
26//!
27//! Both are applied via their corresponding layer types ([`RequestBodyTimeoutLayer`] /
28//! [`RequestBodyDeadlineLayer`] for request bodies, [`ResponseBodyTimeoutLayer`] /
29//! [`ResponseBodyDeadlineLayer`] for response bodies). They can be stacked if you
30//! want both an idle timeout and an absolute deadline.
31//!
32//! # Example
33//!
34//! ```
35//! use std::{convert::Infallible, time::Duration};
36//!
37//! use rama_core::Layer;
38//! use rama_core::service::service_fn;
39//! use rama_http::{Body, Request, Response, StatusCode};
40//! use rama_http::layer::timeout::TimeoutLayer;
41//! use rama_core::error::BoxError;
42//!
43//! async fn handle(_: Request) -> Result<Response, Infallible> {
44//! // ...
45//! # Ok(Response::new(Body::empty()))
46//! }
47//!
48//! # #[tokio::main]
49//! # async fn main() -> Result<(), BoxError> {
50//! let svc = (
51//! // Timeout requests after 30 seconds with the specified status code
52//! TimeoutLayer::with_status_code(StatusCode::REQUEST_TIMEOUT, Duration::from_secs(30)),
53//! ).into_layer(service_fn(handle));
54//! # Ok(())
55//! # }
56//! ```
57//!
58//! [`Infallible`]: std::convert::Infallible
59
60mod body;
61mod deadline_body;
62mod service;
63
64pub use body::{TimeoutBody, TimeoutError};
65pub use deadline_body::DeadlineBody;
66pub use service::{
67 RequestBodyDeadline, RequestBodyDeadlineLayer, RequestBodyTimeout, RequestBodyTimeoutLayer,
68 ResponseBodyDeadline, ResponseBodyDeadlineLayer, ResponseBodyTimeout, ResponseBodyTimeoutLayer,
69 Timeout, TimeoutCause, TimeoutLayer,
70};