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