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}