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}