reqwest_middleware/
middleware.rs

1use reqwest::{Client, Request, Response};
2use std::sync::Arc;
3use task_local_extensions::Extensions;
4
5use crate::error::{Error, Result};
6
7/// When attached to a [`ClientWithMiddleware`] (generally using [`with`]), middleware is run
8/// whenever the client issues a request, in the order it was attached.
9///
10/// # Example
11///
12/// ```
13/// use reqwest::{Client, Request, Response};
14/// use reqwest_middleware::{ClientBuilder, Middleware, Next, Result};
15/// use task_local_extensions::Extensions;
16///
17/// struct TransparentMiddleware;
18///
19/// #[async_trait::async_trait]
20/// impl Middleware for TransparentMiddleware {
21///     async fn handle(
22///         &self,
23///         req: Request,
24///         extensions: &mut Extensions,
25///         next: Next<'_>,
26///     ) -> Result<Response> {
27///         next.run(req, extensions).await
28///     }
29/// }
30/// ```
31///
32/// [`ClientWithMiddleware`]: crate::ClientWithMiddleware
33/// [`with`]: crate::ClientBuilder::with
34#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)]
35#[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))]
36pub trait Middleware: 'static + Send + Sync {
37    /// Invoked with a request before sending it. If you want to continue processing the request,
38    /// you should explicitly call `next.run(req, extensions)`.
39    ///
40    /// If you need to forward data down the middleware stack, you can use the `extensions`
41    /// argument.
42    async fn handle(
43        &self,
44        req: Request,
45        extensions: &mut Extensions,
46        next: Next<'_>,
47    ) -> Result<Response>;
48}
49
50#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)]
51#[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))]
52impl<F> Middleware for F
53where
54    F: Send
55        + Sync
56        + 'static
57        + for<'a> Fn(Request, &'a mut Extensions, Next<'a>) -> BoxFuture<'a, Result<Response>>,
58{
59    async fn handle(
60        &self,
61        req: Request,
62        extensions: &mut Extensions,
63        next: Next<'_>,
64    ) -> Result<Response> {
65        (self)(req, extensions, next).await
66    }
67}
68
69/// Next encapsulates the remaining middleware chain to run in [`Middleware::handle`]. You can
70/// forward the request down the chain with [`run`].
71///
72/// [`Middleware::handle`]: Middleware::handle
73/// [`run`]: Self::run
74#[derive(Clone)]
75pub struct Next<'a> {
76    client: &'a Client,
77    middlewares: &'a [Arc<dyn Middleware>],
78}
79
80#[cfg(not(target_arch = "wasm32"))]
81pub type BoxFuture<'a, T> = std::pin::Pin<Box<dyn std::future::Future<Output = T> + Send + 'a>>;
82#[cfg(target_arch = "wasm32")]
83pub type BoxFuture<'a, T> = std::pin::Pin<Box<dyn std::future::Future<Output = T> + 'a>>;
84
85impl<'a> Next<'a> {
86    pub(crate) fn new(client: &'a Client, middlewares: &'a [Arc<dyn Middleware>]) -> Self {
87        Next {
88            client,
89            middlewares,
90        }
91    }
92
93    pub fn run(
94        mut self,
95        req: Request,
96        extensions: &'a mut Extensions,
97    ) -> BoxFuture<'a, Result<Response>> {
98        if let Some((current, rest)) = self.middlewares.split_first() {
99            self.middlewares = rest;
100            Box::pin(current.handle(req, extensions, self))
101        } else {
102            Box::pin(async move { self.client.execute(req).await.map_err(Error::from) })
103        }
104    }
105}