http_kit/
middleware.rs

1//! Middleware functionality for HTTP request and response processing.
2//!
3//! This module provides the core infrastructure for implementing middleware in the HTTP processing
4//! pipeline. Middleware allows you to modify or inspect HTTP requests and responses during processing,
5//! enabling functionality like:
6//!
7//! - Request/response logging
8//! - Authentication and authorization
9//! - Request timeouts
10//! - Response compression
11//! - Custom headers
12//! - Request/response transformation
13//!
14//! # Usage
15//!
16//! Implement the [`Middleware`] trait to create custom middleware:
17//!
18//! ```rust
19//! use http_kit::{Request, Response, Result, Endpoint, middleware::Middleware, BoxHttpError};
20//! use http_kit::middleware::MiddlewareError;
21//!
22//! struct MyMiddleware;
23//!
24//! impl Middleware for MyMiddleware {
25//!     type Error = BoxHttpError;
26//!     async fn handle<E: Endpoint>(&mut self, request: &mut Request, mut next: E) -> Result<Response, MiddlewareError<E::Error, Self::Error>> {
27//!         // Pre-processing
28//!         let response = next.respond(request).await.map_err(MiddlewareError::Endpoint)?;
29//!         // Post-processing
30//!         Ok(response)
31//!     }
32//! }
33//! ```
34//!
35//! The middleware can then be composed with endpoints using [`WithMiddleware`].
36//! Multiple middleware can be chained together using tuples like `(Middleware1, Middleware2)`.
37use crate::{endpoint::EndpointImpl, error::BoxHttpError, Endpoint, HttpError, Request, Response};
38use alloc::boxed::Box;
39use core::{
40    any::type_name,
41    convert::Infallible,
42    fmt::{Debug, Display},
43    future::Future,
44    ops::DerefMut,
45    pin::Pin,
46};
47use http::StatusCode;
48/// Trait for implementing middleware that can process HTTP requests and responses.
49///
50/// Middleware sits between the initial request and the final endpoint, allowing you to
51/// implement cross-cutting concerns like authentication, logging, rate limiting, compression,
52/// and other request/response transformations.
53///
54/// Middleware operates in a chain where each middleware can:
55/// - Inspect and modify the incoming request
56/// - Decide whether to call the next middleware/endpoint in the chain
57/// - Inspect and modify the outgoing response
58/// - Handle errors and implement fallback behavior
59///
60/// # Implementation Pattern
61///
62/// A typical middleware implementation follows this pattern:
63/// 1. Pre-process the request (logging, validation, etc.)
64/// 2. Call `next.respond(request).await` to continue the chain
65/// 3. Post-process the response (add headers, transform body, etc.)
66/// 4. Return the final response
67///
68/// # Examples
69///
70/// ## Request Logging Middleware
71///
72/// ```rust
73/// use http_kit::{Request, Response, Result, Middleware, Endpoint, Body, BoxHttpError};
74/// use http_kit::middleware::MiddlewareError;
75///
76/// struct LoggingMiddleware;
77///
78/// impl Middleware for LoggingMiddleware {
79///     type Error = BoxHttpError;
80///     async fn handle<E: Endpoint>(&mut self, request: &mut Request, mut next: E) -> Result<Response, MiddlewareError<E::Error, Self::Error>> {
81///         println!("Incoming: {} {}", request.method(), request.uri());
82///
83///         let response = next.respond(request).await.map_err(MiddlewareError::Endpoint)?;
84///
85///         println!("Outgoing: {}", response.status());
86///         Ok(response)
87///     }
88/// }
89/// ```
90///
91/// ## Authentication Middleware
92///
93/// ```rust
94/// use http_kit::{Request, Response, Result, Middleware, Endpoint, StatusCode, Body, BoxHttpError};
95/// use http_kit::middleware::MiddlewareError;
96///
97/// struct AuthMiddleware {
98///     required_token: String,
99/// }
100///
101/// impl Middleware for AuthMiddleware {
102///     type Error = BoxHttpError;
103///     async fn handle<E: Endpoint>(&mut self, request: &mut Request, mut next: E) -> Result<Response, MiddlewareError<E::Error, Self::Error>> {
104///         if let Some(auth_header) = request.headers().get(http::header::AUTHORIZATION) {
105///             if auth_header.as_bytes() == self.required_token.as_bytes() {
106///                 return next.respond(request).await.map_err(MiddlewareError::Endpoint);
107///             }
108///         }
109///
110///         Ok(Response::new(Body::from_bytes("Authentication required")))
111///     }
112/// }
113/// ```
114///
115/// ## Response Header Middleware
116///
117/// ```rust
118/// use http_kit::{Request, Response, Result, Middleware, Endpoint, Body, BoxHttpError};
119/// use http_kit::middleware::MiddlewareError;
120///
121/// struct HeaderMiddleware;
122///
123/// impl Middleware for HeaderMiddleware {
124///     type Error = BoxHttpError;
125///     async fn handle<E: Endpoint>(&mut self, request: &mut Request, mut next: E) -> Result<Response, MiddlewareError<E::Error, Self::Error>> {
126///         let mut response = next.respond(request).await.map_err(MiddlewareError::Endpoint)?;
127///
128///         response.headers_mut().insert(
129///             http::header::SERVER,
130///             http::HeaderValue::from_static("http-kit/1.0")
131///         );
132///
133///         Ok(response)
134///     }
135/// }
136/// ```
137pub trait Middleware: Send {
138    /// The error type that this middleware can produce.
139    type Error: HttpError;
140    /// Processes a request through the middleware chain.
141    ///
142    /// This method receives the current request and a `next` parameter representing
143    /// the next step in the processing chain (either another middleware or the final endpoint).
144    /// The middleware can:
145    ///
146    /// - Modify the request before passing it to `next`
147    /// - Decide whether to call `next` at all (for auth, rate limiting, etc.)
148    /// - Transform the response returned by `next`
149    /// - Handle errors and provide fallback responses
150    ///
151    /// # Arguments
152    ///
153    /// * `request` - Mutable reference to the HTTP request being processed
154    /// * `next` - The next step in the processing chain (middleware or endpoint)
155    ///
156    /// # Returns
157    ///
158    /// Returns a `Result<Response>` which can either be:
159    /// - `Ok(response)` - A successful HTTP response
160    /// - `Err(error)` - An error with an associated HTTP status code
161    ///
162    /// # Examples
163    ///
164    /// ```rust
165    /// use http_kit::{Request, Response, Result, Middleware, Endpoint, Body, BoxHttpError};
166    /// use http_kit::middleware::MiddlewareError;
167    ///
168    /// struct TimingMiddleware;
169    ///
170    /// impl Middleware for TimingMiddleware {
171    ///     type Error = BoxHttpError;
172    ///     async fn handle<E: Endpoint>(&mut self, request: &mut Request, mut next: E) -> Result<Response, MiddlewareError<E::Error, Self::Error>> {
173    ///         let start = std::time::Instant::now();
174    ///
175    ///         // Call the next middleware or endpoint
176    ///         let response = next.respond(request).await.map_err(MiddlewareError::Endpoint)?;
177    ///
178    ///         let duration = start.elapsed();
179    ///         println!("Request processed in {:?}", duration);
180    ///
181    ///         Ok(response)
182    ///     }
183    /// }
184    /// ```
185    fn handle<E: Endpoint>(
186        &mut self,
187        request: &mut Request,
188        next: E,
189    ) -> impl Future<Output = Result<Response, MiddlewareError<E::Error, Self::Error>>> + Send;
190}
191
192/// Error type for middleware that can represent errors from either the middleware itself or the endpoint it wraps.
193#[derive(Debug)]
194pub enum MiddlewareError<N, E> {
195    /// Error originating from the endpoint being called.
196    Endpoint(N),
197    /// Error originating from the middleware itself.
198    Middleware(E),
199}
200
201impl<N: HttpError, E: HttpError> Display for MiddlewareError<N, E> {
202    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
203        match self {
204            MiddlewareError::Endpoint(e) => write!(f, "Endpoint error: {}", e),
205            MiddlewareError::Middleware(e) => write!(f, "Middleware error: {}", e),
206        }
207    }
208}
209
210impl<N: HttpError, E: HttpError> core::error::Error for MiddlewareError<N, E> {
211    fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
212        match self {
213            MiddlewareError::Endpoint(e) => e.source(),
214            MiddlewareError::Middleware(e) => e.source(),
215        }
216    }
217}
218
219impl<N: HttpError, E: HttpError> HttpError for MiddlewareError<N, E> {
220    fn status(&self) -> StatusCode {
221        match self {
222            MiddlewareError::Endpoint(e) => e.status(),
223            MiddlewareError::Middleware(e) => e.status(),
224        }
225    }
226}
227
228pub(crate) trait MiddlewareImpl: Send {
229    fn handle_inner<'this, 'req, 'next, 'fut>(
230        &'this mut self,
231        request: &'req mut Request,
232        next: &'next mut dyn EndpointImpl,
233    ) -> Pin<Box<dyn 'fut + Future<Output = Result<Response, BoxHttpError>> + Send>>
234    where
235        'this: 'fut,
236        'req: 'fut,
237        'next: 'fut;
238    fn name(&self) -> &'static str {
239        type_name::<Self>()
240    }
241}
242
243impl<'a> Endpoint for &mut (dyn EndpointImpl + 'a) {
244    type Error = BoxHttpError;
245    async fn respond(&mut self, request: &mut Request) -> Result<Response, Self::Error> {
246        self.respond_inner(request).await
247    }
248}
249
250impl<T: Middleware> MiddlewareImpl for T {
251    fn handle_inner<'this, 'req, 'next, 'fut>(
252        &'this mut self,
253        request: &'req mut Request,
254        next: &'next mut dyn EndpointImpl,
255    ) -> Pin<Box<dyn 'fut + Future<Output = Result<Response, BoxHttpError>> + Send>>
256    where
257        'this: 'fut,
258        'req: 'fut,
259        'next: 'fut,
260    {
261        Box::pin(async move {
262            self.handle(request, next)
263                .await
264                .map_err(|e| Box::new(e) as BoxHttpError)
265        })
266    }
267}
268
269impl<M: Middleware> Middleware for &mut M {
270    type Error = M::Error;
271    async fn handle<E: Endpoint>(
272        &mut self,
273        request: &mut Request,
274        next: E,
275    ) -> Result<Response, MiddlewareError<E::Error, Self::Error>> {
276        Middleware::handle(*self, request, next).await
277    }
278}
279
280impl<M: Middleware> Middleware for Box<M> {
281    type Error = M::Error;
282    async fn handle<E: Endpoint>(
283        &mut self,
284        request: &mut Request,
285        next: E,
286    ) -> Result<Response, MiddlewareError<E::Error, Self::Error>> {
287        Middleware::handle(self.deref_mut(), request, next).await
288    }
289}
290
291/// Error type for middleware tuples, representing errors from either middleware.
292#[derive(Debug)]
293pub enum MiddlewareTupleError<E1: HttpError, E2: HttpError> {
294    /// Error from the first middleware in the tuple.
295    First(E1),
296    /// Error from the second middleware in the tuple.
297    Second(E2),
298}
299
300impl<A, B> Display for MiddlewareTupleError<A, B>
301where
302    A: HttpError,
303    B: HttpError,
304{
305    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
306        match self {
307            MiddlewareTupleError::First(e) => write!(f, "First middleware error: {}", e),
308            MiddlewareTupleError::Second(e) => write!(f, "Second middleware error: {}", e),
309        }
310    }
311}
312
313impl<A, B> core::error::Error for MiddlewareTupleError<A, B>
314where
315    A: HttpError,
316    B: HttpError,
317{
318    fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
319        match self {
320            MiddlewareTupleError::First(e) => e.source(),
321            MiddlewareTupleError::Second(e) => e.source(),
322        }
323    }
324}
325
326impl<A, B> HttpError for MiddlewareTupleError<A, B>
327where
328    A: HttpError,
329    B: HttpError,
330{
331    fn status(&self) -> StatusCode {
332        match self {
333            MiddlewareTupleError::First(e) => e.status(),
334            MiddlewareTupleError::Second(e) => e.status(),
335        }
336    }
337}
338
339/// Type-erased middleware that can hold any middleware implementation behind a trait object.
340///
341/// `AnyMiddleware` provides dynamic dispatch for middleware, allowing you to store
342/// different middleware types in the same collection or pass them around without
343/// knowing their concrete types at compile time. This is particularly useful for:
344///
345/// - Building flexible middleware chains with different middleware types
346/// - Plugin systems where middleware is loaded dynamically
347/// - Configuration-driven middleware stacks
348/// - Storing middleware in collections or registries
349pub struct AnyMiddleware(Box<dyn MiddlewareImpl>);
350
351impl Debug for AnyMiddleware {
352    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
353        f.write_fmt(format_args!("AnyMiddleware[{}]", self.name()))
354    }
355}
356
357impl AnyMiddleware {
358    /// Creates a new type-erased middleware wrapper around the given middleware implementation.
359    ///
360    /// This method takes any type that implements `Middleware` and wraps it in an
361    /// `AnyMiddleware` that can be stored alongside other middleware of different types.
362    /// The original middleware type information is erased, but the functionality is preserved.
363    ///
364    /// # Arguments
365    ///
366    /// * `middleware` - Any middleware implementation
367    ///
368    /// # Examples
369    ///
370    /// ```rust
371    /// use http_kit::{Request, Response, Result, Middleware, Endpoint, middleware::AnyMiddleware, Body, BoxHttpError};
372    /// use http_kit::middleware::MiddlewareError;
373    ///
374    /// struct CustomMiddleware {
375    ///     prefix: String,
376    /// }
377    ///
378    /// impl Middleware for CustomMiddleware {
379    ///     type Error = BoxHttpError;
380    ///     async fn handle<E: Endpoint>(&mut self, request: &mut Request, mut next: E) -> Result<Response, MiddlewareError<E::Error, Self::Error>> {
381    ///         println!("{}: Processing {}", self.prefix, request.uri());
382    ///         next.respond(request).await.map_err(MiddlewareError::Endpoint)
383    ///     }
384    /// }
385    ///
386    /// let middleware = CustomMiddleware { prefix: "API".to_string() };
387    /// let any_middleware = AnyMiddleware::new(middleware);
388    /// ```
389    pub fn new(middleware: impl Middleware + 'static) -> Self {
390        AnyMiddleware(Box::new(middleware))
391    }
392
393    /// Returns the type name of the underlying middleware implementation.
394    ///
395    /// This method provides introspection capabilities for debugging, logging,
396    /// or monitoring purposes. The returned string is the fully qualified type name
397    /// of the original middleware type.
398    ///
399    /// # Examples
400    ///
401    /// ```rust
402    /// use http_kit::{Request, Response, Result, Middleware, Endpoint, middleware::AnyMiddleware, Body, BoxHttpError};
403    /// use http_kit::middleware::MiddlewareError;
404    ///
405    /// struct MyMiddleware;
406    /// impl Middleware for MyMiddleware {
407    ///     type Error = BoxHttpError;
408    ///     async fn handle<E: Endpoint>(&mut self, request: &mut Request, mut next: E) -> Result<Response, MiddlewareError<E::Error, Self::Error>> {
409    ///         next.respond(request).await.map_err(MiddlewareError::Endpoint)
410    ///     }
411    /// }
412    ///
413    /// let any_middleware = AnyMiddleware::new(MyMiddleware);
414    /// println!("Middleware type: {}", any_middleware.name());
415    /// // Output: Middleware type: my_crate::MyMiddleware
416    /// ```
417    pub fn name(&self) -> &'static str {
418        self.0.name()
419    }
420}
421
422impl Middleware for AnyMiddleware {
423    type Error = BoxHttpError;
424    async fn handle<E: Endpoint>(
425        &mut self,
426        request: &mut Request,
427        mut next: E,
428    ) -> Result<Response, MiddlewareError<E::Error, Self::Error>> {
429        self.0
430            .handle_inner(request, &mut next)
431            .await
432            .map_err(MiddlewareError::<E::Error, _>::Middleware)
433    }
434}
435
436/// No-op middleware implementation for the unit type.
437///
438/// This implementation allows `()` to be used as a middleware that does nothing
439/// but pass the request through to the next handler. This is useful for:
440/// - Default values in generic contexts
441/// - Conditional middleware application
442/// - Testing scenarios where middleware is optional
443impl Middleware for () {
444    type Error = Infallible;
445    async fn handle<E: Endpoint>(
446        &mut self,
447        request: &mut Request,
448        mut next: E,
449    ) -> Result<Response, MiddlewareError<E::Error, Self::Error>> {
450        next.respond(request)
451            .await
452            .map_err(MiddlewareError::<_, Self::Error>::Endpoint)
453    }
454}