Skip to main content

siderite_core/
middleware.rs

1//! Middleware: tower layers over the whole application, plus batteries.
2//!
3//! [`App::layer`] accepts any `tower::Layer` over [`BoxService`], the
4//! application as a `Service<http::Request<Body>>`. [`from_fn`] builds one
5//! from an async function.
6//!
7//! # Ordering
8//! **The first layer registered is the outermost**: it sees the request first
9//! and the response last, exactly like reading `ServiceBuilder` top to bottom.
10//! `app.request_id().request_logging().cors(..)` runs request-id, then
11//! logging, then CORS, then the routes. Registration order relative to
12//! `with_state`, `provide`, ... does not matter: middleware always wraps
13//! those. Middleware of the root app also wraps 404s and the documentation
14//! endpoints; middleware of a mounted child wraps only that child's routes.
15//!
16//! # Errors
17//! Rejections produced by built-in middleware are RFC 7807
18//! `application/problem+json` documents ([`ApiError`](crate::ApiError)).
19//!
20//! # Built-ins
21//! [`Cors`], [`Compression`], [`CsrfOrigin`], [`TrustedHosts`],
22//! [`HttpsRedirect`], [`RequestIdLayer`] (+ [`RequestId`] extractor),
23//! [`RequestLogging`], [`Timeout`], [`ConcurrencyLimit`], [`BodyLimit`] and
24//! [`RateLimit`], each with a same-named convenience method on [`App`].
25
26mod adapt;
27mod cors;
28mod csrf;
29mod hosts;
30mod limits;
31mod observe;
32
33use crate::app::App;
34use crate::extract::Request;
35use crate::response::Response;
36use std::convert::Infallible;
37use std::time::Duration;
38use tower::{Layer, Service};
39
40pub use adapt::{BoxService, FromFnLayer, Next, from_fn};
41pub use cors::{Compression, Cors};
42pub use csrf::{CsrfOrigin, CsrfOriginError};
43pub use hosts::{HttpsRedirect, TrustedHosts};
44mod concurrency;
45pub use concurrency::{ConcurrencyLimit, ConcurrencyLimitError, ConcurrencyStats};
46pub use limits::{BodyLimit, Timeout};
47mod proxy;
48mod rate_limit;
49pub use observe::{RequestId, RequestIdLayer, RequestLogging};
50pub use proxy::{ProxyContext, ProxyError, TrustedProxies};
51pub use rate_limit::{RateLimit, RateLimitError};
52
53pub(crate) use observe::note_matched_path;
54
55impl App {
56    /// Wrap the application in `layer`. See the [module docs](self) for the
57    /// ordering rules.
58    #[must_use]
59    pub fn layer<L>(mut self, layer: L) -> Self
60    where
61        L: Layer<BoxService> + Clone + Send + Sync + 'static,
62        L::Service: Service<Request, Response = Response, Error = Infallible>
63            + Clone
64            + Send
65            + Sync
66            + 'static,
67        <L::Service as Service<Request>>::Future: Send + 'static,
68    {
69        self.middleware
70            .push(Box::new(move |router| adapt::apply_layer(&layer, router)));
71        self
72    }
73
74    /// Add [`Cors`] middleware.
75    #[must_use]
76    pub fn cors(self, cors: Cors) -> Self {
77        self.layer(cors)
78    }
79
80    /// Add [`Compression`] middleware.
81    #[must_use]
82    pub fn compression(self, compression: Compression) -> Self {
83        self.layer(compression)
84    }
85
86    /// Add [`CsrfOrigin`] middleware.
87    #[must_use]
88    pub fn csrf_origin(self, csrf: CsrfOrigin) -> Self {
89        self.layer(csrf)
90    }
91
92    /// Add [`TrustedHosts`] middleware.
93    #[must_use]
94    pub fn trusted_hosts(self, hosts: TrustedHosts) -> Self {
95        self.layer(hosts)
96    }
97
98    /// Add [`HttpsRedirect`] middleware.
99    #[must_use]
100    pub fn https_redirect(self, redirect: HttpsRedirect) -> Self {
101        self.layer(redirect)
102    }
103
104    /// Add request-id middleware with default settings.
105    #[must_use]
106    pub fn request_id(self) -> Self {
107        self.layer(RequestIdLayer::new())
108    }
109
110    /// Add [`RequestLogging`] middleware.
111    #[must_use]
112    pub fn request_logging(self) -> Self {
113        self.layer(RequestLogging::new())
114    }
115
116    /// Add a [`Timeout`] (504 by default).
117    #[must_use]
118    pub fn timeout(self, limit: Duration) -> Self {
119        self.layer(Timeout::new(limit))
120    }
121
122    /// Add a [`ConcurrencyLimit`].
123    #[must_use]
124    pub fn concurrency_limit(mut self, max: usize) -> Self {
125        let limit = ConcurrencyLimit::new(max);
126        if let Err(error) = limit.validate() {
127            self.config_errors.push(error.to_string());
128        }
129        self.layer(limit)
130    }
131
132    /// Add a [`BodyLimit`] of `max_bytes`.
133    #[must_use]
134    pub fn body_limit(self, max_bytes: usize) -> Self {
135        self.layer(BodyLimit::new(max_bytes))
136    }
137
138    /// Add a [`RateLimit`].
139    #[must_use]
140    pub fn rate_limit(mut self, limit: RateLimit) -> Self {
141        if !limit.valid() {
142            self.config_errors
143                .push("invalid rate limiter configuration".into());
144        }
145        self.layer(limit)
146    }
147}