surf/middleware/
mod.rs

1//! Middleware types
2//!
3//! # Examples
4//! ```no_run
5//! use surf::middleware::{Next, Middleware};
6//! use surf::{Client, Request, Response, Result};
7//! use std::time;
8//! use std::sync::Arc;
9//!
10//! /// Log each request's duration
11//! #[derive(Debug)]
12//! pub struct Logger;
13//!
14//! #[surf::utils::async_trait]
15//! impl Middleware for Logger {
16//!     async fn handle(
17//!         &self,
18//!         req: Request,
19//!         client: Client,
20//!         next: Next<'_>,
21//!     ) -> Result<Response> {
22//!         println!("sending request to {}", req.url());
23//!         let now = time::Instant::now();
24//!         let res = next.run(req, client).await?;
25//!         println!("request completed ({:?})", now.elapsed());
26//!         Ok(res)
27//!     }
28//! }
29//! ```
30//! `Middleware` can also be instantiated using a free function thanks to some convenient trait
31//! implementations.
32//!
33//! ```no_run
34//! use futures_util::future::BoxFuture;
35//! use surf::middleware::{Next, Middleware};
36//! use surf::{Client, Request, Response, Result};
37//! use std::time;
38//! use std::sync::Arc;
39//!
40//! fn logger<'a>(req: Request, client: Client, next: Next<'a>) -> BoxFuture<'a, Result<Response>> {
41//!     Box::pin(async move {
42//!         println!("sending request to {}", req.url());
43//!         let now = time::Instant::now();
44//!         let res = next.run(req, client).await?;
45//!         println!("request completed ({:?})", now.elapsed());
46//!         Ok(res)
47//!     })
48//! }
49//! #
50//! # #[async_std::main]
51//! # async fn main() -> Result<()> {
52//! #     surf::client().with(logger);
53//! #     Ok(())
54//! # }
55//! ```
56
57use std::sync::Arc;
58
59use crate::{Client, Request, Response, Result};
60
61mod logger;
62mod redirect;
63
64pub use logger::Logger;
65pub use redirect::Redirect;
66
67use async_trait::async_trait;
68use futures_util::future::BoxFuture;
69
70/// Middleware that wraps around remaining middleware chain.
71#[async_trait]
72pub trait Middleware: 'static + Send + Sync {
73    /// Asynchronously handle the request, and return a response.
74    async fn handle(&self, req: Request, client: Client, next: Next<'_>) -> Result<Response>;
75}
76
77// This allows functions to work as middleware too.
78#[async_trait]
79impl<F> Middleware for F
80where
81    F: Send
82        + Sync
83        + 'static
84        + for<'a> Fn(Request, Client, Next<'a>) -> BoxFuture<'a, Result<Response>>,
85{
86    async fn handle(&self, req: Request, client: Client, next: Next<'_>) -> Result<Response> {
87        (self)(req, client, next).await
88    }
89}
90
91/// The remainder of a middleware chain, including the endpoint.
92#[allow(missing_debug_implementations)]
93pub struct Next<'a> {
94    next_middleware: &'a [Arc<dyn Middleware>],
95    endpoint: &'a (dyn (Fn(Request, Client) -> BoxFuture<'static, Result<Response>>)
96             + Send
97             + Sync
98             + 'static),
99}
100
101impl Clone for Next<'_> {
102    fn clone(&self) -> Self {
103        Self {
104            next_middleware: self.next_middleware,
105            endpoint: self.endpoint,
106        }
107    }
108}
109
110impl Copy for Next<'_> {}
111
112impl<'a> Next<'a> {
113    /// Create a new instance
114    pub fn new(
115        next: &'a [Arc<dyn Middleware>],
116        endpoint: &'a (dyn (Fn(Request, Client) -> BoxFuture<'static, Result<Response>>)
117                 + Send
118                 + Sync
119                 + 'static),
120    ) -> Self {
121        Self {
122            endpoint,
123            next_middleware: next,
124        }
125    }
126
127    /// Asynchronously execute the remaining middleware chain.
128    pub fn run(mut self, req: Request, client: Client) -> BoxFuture<'a, Result<Response>> {
129        if let Some((current, next)) = self.next_middleware.split_first() {
130            self.next_middleware = next;
131            current.handle(req, client, self)
132        } else {
133            (self.endpoint)(req, client)
134        }
135    }
136}