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