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}