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