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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
//! A collection of common middleware.
//!
//! # What Is Middleware?
//!
//! Actix Web's middleware system allows us to add additional behavior to request/response
//! processing. Middleware can hook into incoming request and outgoing response processes, enabling
//! us to modify requests and responses as well as halt request processing to return a response
//! early.
//!
//! Typically, middleware is involved in the following actions:
//!
//! - Pre-process the request (e.g., [normalizing paths](NormalizePath))
//! - Post-process a response (e.g., [logging][Logger])
//! - Modify application state (through [`ServiceRequest`][crate::dev::ServiceRequest])
//! - Access external services (e.g., [sessions](https://docs.rs/actix-session), etc.)
//!
//! Middleware is registered for each [`App`], [`Scope`](crate::Scope), or
//! [`Resource`](crate::Resource) and executed in opposite order as registration. In general, a
//! middleware is a pair of types that implements the [`Service`] trait and [`Transform`] trait,
//! respectively. The [`new_transform`] and [`call`] methods must return a [`Future`], though it
//! can often be [an immediately-ready one](actix_utils::future::Ready).
//!
//! # Ordering
//!
//! ```
//! # use actix_web::{web, middleware, get, App, Responder};
//! #
//! # // some basic types to make sure this compiles
//! # type ExtractorA = web::Json<String>;
//! # type ExtractorB = ExtractorA;
//! #[get("/")]
//! async fn service(a: ExtractorA, b: ExtractorB) -> impl Responder { "Hello, World!" }
//!
//! # fn main() {
//! # // These aren't snake_case, because they are supposed to be unit structs.
//! # let MiddlewareA = middleware::Compress::default();
//! # let MiddlewareB = middleware::Compress::default();
//! # let MiddlewareC = middleware::Compress::default();
//! let app = App::new()
//!     .wrap(MiddlewareA)
//!     .wrap(MiddlewareB)
//!     .wrap(MiddlewareC)
//!     .service(service);
//! # }
//! ```
//!
//! ```plain
//!                   Request
//!                      ⭣
//! ╭────────────────────┼────╮
//! │ MiddlewareC        │    │
//! │ ╭──────────────────┼───╮│
//! │ │ MiddlewareB      │   ││
//! │ │ ╭────────────────┼──╮││
//! │ │ │ MiddlewareA    │  │││
//! │ │ │ ╭──────────────┼─╮│││
//! │ │ │ │ ExtractorA   │ ││││
//! │ │ │ ├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┼┈┤│││
//! │ │ │ │ ExtractorB   │ ││││
//! │ │ │ ├┈┈┈┈┈┈┈┈┈┈┈┈┈┈┼┈┤│││
//! │ │ │ │ service      │ ││││
//! │ │ │ ╰──────────────┼─╯│││
//! │ │ ╰────────────────┼──╯││
//! │ ╰──────────────────┼───╯│
//! ╰────────────────────┼────╯
//!                      ⭣
//!                   Response
//! ```
//! The request _first_ gets processed by the middleware specified _last_ - `MiddlewareC`. It passes
//! the request (modified a modified one) to the next middleware - `MiddlewareB` - _or_ directly
//! responds to the request (e.g. when the request was invalid or an error occurred). `MiddlewareB`
//! processes the request as well and passes it to `MiddlewareA`, which then passes it to the
//! [`Service`]. In the [`Service`], the extractors will run first. They don't pass the request on,
//! but only view it (see [`FromRequest`]). After the [`Service`] responds to the request, the
//! response is passed back through `MiddlewareA`, `MiddlewareB`, and `MiddlewareC`.
//!
//! As you register middleware using [`wrap`][crate::App::wrap] and [`wrap_fn`][crate::App::wrap_fn]
//! in the [`App`] builder, imagine wrapping layers around an inner [`App`]. The first middleware
//! layer exposed to a Request is the outermost layer (i.e., the _last_ registered in the builder
//! chain, in the example above: `MiddlewareC`). Consequently, the _first_ middleware registered in
//! the builder chain is the _last_ to start executing during request processing (`MiddlewareA`).
//! Ordering is less obvious when wrapped services also have middleware applied. In this case,
//! middleware are run in reverse order for [`App`] _and then_ in reverse order for the wrapped
//! service.
//!
//! # Middleware Traits
//!
//! ## `Transform<S, Req>`
//!
//! The [`Transform`] trait is the builder for the actual [`Service`]s that handle the requests. All
//! the middleware you pass to the `wrap` methods implement this trait. During construction, each
//! thread assembles a chain of [`Service`]s by calling [`new_transform`] and passing the next
//! [`Service`] (`S`) in the chain. The created [`Service`] handles requests of type `Req`.
//!
//! In the example from the [ordering](#ordering) section, the chain would be:
//!
//! ```plain
//! MiddlewareCService {
//!     next: MiddlewareBService {
//!         next: MiddlewareAService { ... }
//!     }
//! }
//! ```
//!
//! ## `Service<Req>`
//!
//! A [`Service`] `S` represents an asynchronous operation that turns a request of type `Req` into a
//! response of type [`S::Response`](crate::dev::Service::Response) or an error of type
//! [`S::Error`](crate::dev::Service::Error). You can think of the service of being roughly:
//!
//! ```ignore
//! async fn(&self, req: Req) -> Result<S::Response, S::Error>
//! ```
//!
//! In most cases the [`Service`] implementation will, at some point, call the wrapped [`Service`]
//! in its [`call`] implementation.
//!
//! Note that the [`Service`]s created by [`new_transform`] don't need to be [`Send`] or [`Sync`].
//!
//! # Example
//!
//! ```
//! use std::{future::{ready, Ready, Future}, pin::Pin};
//!
//! use actix_web::{
//!     dev::{forward_ready, Service, ServiceRequest, ServiceResponse, Transform},
//!     web, Error,
//! #   App
//! };
//!
//! pub struct SayHi;
//!
//! // `S` - type of the next service
//! // `B` - type of response's body
//! impl<S, B> Transform<S, ServiceRequest> for SayHi
//! where
//!     S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
//!     S::Future: 'static,
//!     B: 'static,
//! {
//!     type Response = ServiceResponse<B>;
//!     type Error = Error;
//!     type InitError = ();
//!     type Transform = SayHiMiddleware<S>;
//!     type Future = Ready<Result<Self::Transform, Self::InitError>>;
//!
//!     fn new_transform(&self, service: S) -> Self::Future {
//!         ready(Ok(SayHiMiddleware { service }))
//!     }
//! }
//!
//! pub struct SayHiMiddleware<S> {
//!     /// The next service to call
//!     service: S,
//! }
//!
//! // This future doesn't have the requirement of being `Send`.
//! // See: futures_util::future::LocalBoxFuture
//! type LocalBoxFuture<T> = Pin<Box<dyn Future<Output = T> + 'static>>;
//!
//! // `S`: type of the wrapped service
//! // `B`: type of the body - try to be generic over the body where possible
//! impl<S, B> Service<ServiceRequest> for SayHiMiddleware<S>
//! where
//!     S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
//!     S::Future: 'static,
//!     B: 'static,
//! {
//!     type Response = ServiceResponse<B>;
//!     type Error = Error;
//!     type Future = LocalBoxFuture<Result<Self::Response, Self::Error>>;
//!
//!     // This service is ready when its next service is ready
//!     forward_ready!(service);
//!
//!     fn call(&self, req: ServiceRequest) -> Self::Future {
//!         println!("Hi from start. You requested: {}", req.path());
//!
//!         // A more complex middleware, could return an error or an early response here.
//!
//!         let fut = self.service.call(req);
//!
//!         Box::pin(async move {
//!             let res = fut.await?;
//!
//!             println!("Hi from response");
//!             Ok(res)
//!         })
//!     }
//! }
//!
//! # fn main() {
//! let app = App::new()
//!     .wrap(SayHi)
//!     .route("/", web::get().to(|| async { "Hello, middleware!" }));
//! # }
//! ```
//!
//! # Simpler Middleware
//!
//! In many cases, you _can_ actually use an async function via a helper that will provide a more
//! natural flow for your behavior.
//!
//! The experimental `actix_web_lab` crate provides a [`from_fn`][lab_from_fn] utility which allows
//! an async fn to be wrapped and used in the same way as other middleware. See the
//! [`from_fn`][lab_from_fn] docs for more info and examples of it's use.
//!
//! While [`from_fn`][lab_from_fn] is experimental currently, it's likely this helper will graduate
//! to Actix Web in some form, so feedback is appreciated.
//!
//! [`Future`]: std::future::Future
//! [`App`]: crate::App
//! [`FromRequest`]: crate::FromRequest
//! [`Service`]: crate::dev::Service
//! [`Transform`]: crate::dev::Transform
//! [`call`]: crate::dev::Service::call()
//! [`new_transform`]: crate::dev::Transform::new_transform()
//! [lab_from_fn]: https://docs.rs/actix-web-lab/latest/actix_web_lab/middleware/fn.from_fn.html

mod compat;
mod condition;
mod default_headers;
mod err_handlers;
mod logger;
#[cfg(test)]
mod noop;
mod normalize;

#[cfg(test)]
pub(crate) use self::noop::Noop;
pub use self::{
    compat::Compat,
    condition::Condition,
    default_headers::DefaultHeaders,
    err_handlers::{ErrorHandlerResponse, ErrorHandlers},
    logger::Logger,
    normalize::{NormalizePath, TrailingSlash},
};

#[cfg(feature = "__compress")]
mod compress;

#[cfg(feature = "__compress")]
pub use self::compress::Compress;

#[cfg(test)]
mod tests {
    use super::*;
    use crate::{http::StatusCode, App};

    #[test]
    fn common_combinations() {
        // ensure there's no reason that the built-in middleware cannot compose

        let _ = App::new()
            .wrap(Compat::new(Logger::default()))
            .wrap(Condition::new(true, DefaultHeaders::new()))
            .wrap(DefaultHeaders::new().add(("X-Test2", "X-Value2")))
            .wrap(ErrorHandlers::new().handler(StatusCode::FORBIDDEN, |res| {
                Ok(ErrorHandlerResponse::Response(res.map_into_left_body()))
            }))
            .wrap(Logger::default())
            .wrap(NormalizePath::new(TrailingSlash::Trim));

        let _ = App::new()
            .wrap(NormalizePath::new(TrailingSlash::Trim))
            .wrap(Logger::default())
            .wrap(ErrorHandlers::new().handler(StatusCode::FORBIDDEN, |res| {
                Ok(ErrorHandlerResponse::Response(res.map_into_left_body()))
            }))
            .wrap(DefaultHeaders::new().add(("X-Test2", "X-Value2")))
            .wrap(Condition::new(true, DefaultHeaders::new()))
            .wrap(Compat::new(Logger::default()));

        #[cfg(feature = "__compress")]
        {
            let _ = App::new().wrap(Compress::default()).wrap(Logger::default());
            let _ = App::new().wrap(Logger::default()).wrap(Compress::default());
            let _ = App::new().wrap(Compat::new(Compress::default()));
            let _ = App::new().wrap(Condition::new(true, Compat::new(Compress::default())));
        }
    }
}