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, Error};
20//! use http_kit::middleware::MiddlewareError;
21//!
22//! struct MyMiddleware;
23//!
24//! impl Middleware for MyMiddleware {
25//!     type Error = Error;
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, Error};
74/// use http_kit::middleware::MiddlewareError;
75///
76/// struct LoggingMiddleware;
77///
78/// impl Middleware for LoggingMiddleware {
79///     type Error = Error;
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, Error};
95/// use http_kit::middleware::MiddlewareError;
96///
97/// struct AuthMiddleware {
98///     required_token: String,
99/// }
100///
101/// impl Middleware for AuthMiddleware {
102///     type Error = Error;
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, Error};
119/// use http_kit::middleware::MiddlewareError;
120///
121/// struct HeaderMiddleware;
122///
123/// impl Middleware for HeaderMiddleware {
124///     type Error = Error;
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, Error};
166    /// use http_kit::middleware::MiddlewareError;
167    ///
168    /// struct TimingMiddleware;
169    ///
170    /// impl Middleware for TimingMiddleware {
171    ///     type Error = Error;
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) -> Option<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) -> Option<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
349///
350/// # Performance Considerations
351///
352/// Using `AnyMiddleware` involves dynamic dispatch and heap allocation, which has
353/// a small performance overhead compared to using concrete types directly. However,
354/// this overhead is typically negligible in HTTP server contexts where network I/O
355/// dominates performance characteristics.
356///
357/// # Examples
358///
359/// ## Storing Mixed Middleware Types
360///
361/// ```rust
362/// use http_kit::{Request, Response, Result, Middleware, Endpoint, middleware::AnyMiddleware, Body, Error};
363/// use http_kit::middleware::MiddlewareError;
364///
365/// struct LoggingMiddleware;
366/// impl Middleware for LoggingMiddleware {
367///     type Error = Error;
368///     async fn handle<E: Endpoint>(&mut self, request: &mut Request, mut next: E) -> Result<Response, MiddlewareError<E::Error, Self::Error>> {
369///         println!("Request: {}", request.uri());
370///         next.respond(request).await.map_err(MiddlewareError::Endpoint)
371///     }
372/// }
373///
374/// struct TimingMiddleware;
375/// impl Middleware for TimingMiddleware {
376///     type Error = Error;
377///     async fn handle<E: Endpoint>(&mut self, request: &mut Request, mut next: E) -> Result<Response, MiddlewareError<E::Error, Self::Error>> {
378///         let start = std::time::Instant::now();
379///         let response = next.respond(request).await.map_err(MiddlewareError::Endpoint);
380///         println!("Duration: {:?}", start.elapsed());
381///         response
382///     }
383/// }
384///
385/// // Store different middleware types in a collection
386/// let middleware_stack: Vec<AnyMiddleware> = vec![
387///     AnyMiddleware::new(LoggingMiddleware),
388///     AnyMiddleware::new(TimingMiddleware),
389/// ];
390/// ```
391///
392/// ## Dynamic Middleware Configuration
393///
394/// ```rust
395/// use http_kit::{Request, Response, Result, Middleware, Endpoint, middleware::AnyMiddleware, Body, Error};
396/// use http_kit::middleware::MiddlewareError;
397///
398/// fn create_middleware(name: &str) -> Option<AnyMiddleware> {
399///     match name {
400///         "logging" => Some(AnyMiddleware::new(LoggingMiddleware)),
401///         "timing" => Some(AnyMiddleware::new(TimingMiddleware)),
402///         _ => None,
403///     }
404/// }
405///
406/// # struct LoggingMiddleware;
407/// # impl Middleware for LoggingMiddleware {
408/// #     type Error = Error;
409/// #     async fn handle<E: Endpoint>(&mut self, request: &mut Request, mut next: E) -> Result<Response, MiddlewareError<E::Error, Self::Error>> {
410/// #         next.respond(request).await.map_err(MiddlewareError::Endpoint)
411/// #     }
412/// # }
413/// # struct TimingMiddleware;
414/// # impl Middleware for TimingMiddleware {
415/// #     type Error = Error;
416/// #     async fn handle<E: Endpoint>(&mut self, request: &mut Request, mut next: E) -> Result<Response, MiddlewareError<E::Error, Self::Error>> {
417/// #         next.respond(request).await.map_err(MiddlewareError::Endpoint)
418/// #     }
419/// # }
420/// ```
421pub struct AnyMiddleware(Box<dyn MiddlewareImpl>);
422
423impl Debug for AnyMiddleware {
424    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
425        f.write_fmt(format_args!("AnyMiddleware[{}]", self.name()))
426    }
427}
428
429impl AnyMiddleware {
430    /// Creates a new type-erased middleware wrapper around the given middleware implementation.
431    ///
432    /// This method takes any type that implements `Middleware` and wraps it in an
433    /// `AnyMiddleware` that can be stored alongside other middleware of different types.
434    /// The original middleware type information is erased, but the functionality is preserved.
435    ///
436    /// # Arguments
437    ///
438    /// * `middleware` - Any middleware implementation
439    ///
440    /// # Examples
441    ///
442    /// ```rust
443    /// use http_kit::{Request, Response, Result, Middleware, Endpoint, middleware::AnyMiddleware, Body, Error};
444    /// use http_kit::middleware::MiddlewareError;
445    ///
446    /// struct CustomMiddleware {
447    ///     prefix: String,
448    /// }
449    ///
450    /// impl Middleware for CustomMiddleware {
451    ///     type Error = Error;
452    ///     async fn handle<E: Endpoint>(&mut self, request: &mut Request, mut next: E) -> Result<Response, MiddlewareError<E::Error, Self::Error>> {
453    ///         println!("{}: Processing {}", self.prefix, request.uri());
454    ///         next.respond(request).await.map_err(MiddlewareError::Endpoint)
455    ///     }
456    /// }
457    ///
458    /// let middleware = CustomMiddleware { prefix: "API".to_string() };
459    /// let any_middleware = AnyMiddleware::new(middleware);
460    /// ```
461    pub fn new(middleware: impl Middleware + 'static) -> Self {
462        AnyMiddleware(Box::new(middleware))
463    }
464
465    /// Returns the type name of the underlying middleware implementation.
466    ///
467    /// This method provides introspection capabilities for debugging, logging,
468    /// or monitoring purposes. The returned string is the fully qualified type name
469    /// of the original middleware type.
470    ///
471    /// # Examples
472    ///
473    /// ```rust
474    /// use http_kit::{Request, Response, Result, Middleware, Endpoint, middleware::AnyMiddleware, Body, Error};
475    /// use http_kit::middleware::MiddlewareError;
476    ///
477    /// struct MyMiddleware;
478    /// impl Middleware for MyMiddleware {
479    ///     type Error = Error;
480    ///     async fn handle<E: Endpoint>(&mut self, request: &mut Request, mut next: E) -> Result<Response, MiddlewareError<E::Error, Self::Error>> {
481    ///         next.respond(request).await.map_err(MiddlewareError::Endpoint)
482    ///     }
483    /// }
484    ///
485    /// let any_middleware = AnyMiddleware::new(MyMiddleware);
486    /// println!("Middleware type: {}", any_middleware.name());
487    /// // Output: Middleware type: my_crate::MyMiddleware
488    /// ```
489    pub fn name(&self) -> &'static str {
490        self.0.name()
491    }
492}
493
494impl Middleware for AnyMiddleware {
495    type Error = BoxHttpError;
496    async fn handle<E: Endpoint>(
497        &mut self,
498        request: &mut Request,
499        mut next: E,
500    ) -> Result<Response, MiddlewareError<E::Error, Self::Error>> {
501        self.0
502            .handle_inner(request, &mut next)
503            .await
504            .map_err(MiddlewareError::<E::Error, _>::Middleware)
505    }
506}
507
508/// No-op middleware implementation for the unit type.
509///
510/// This implementation allows `()` to be used as a middleware that does nothing
511/// but pass the request through to the next handler. This is useful for:
512/// - Default values in generic contexts
513/// - Conditional middleware application
514/// - Testing scenarios where middleware is optional
515impl Middleware for () {
516    type Error = Infallible;
517    async fn handle<E: Endpoint>(
518        &mut self,
519        request: &mut Request,
520        mut next: E,
521    ) -> Result<Response, MiddlewareError<E::Error, Self::Error>> {
522        next.respond(request)
523            .await
524            .map_err(MiddlewareError::<_, Self::Error>::Endpoint)
525    }
526}