Middleware chain based on iterator
This commit is contained in:
@@ -134,27 +134,18 @@ pub trait Middleware {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Continuation of a [`Middleware`] chain.
|
/// Continuation of a [`Middleware`] chain.
|
||||||
pub struct MiddlewareNext<'a>(Next<'a>);
|
pub struct MiddlewareNext<'a> {
|
||||||
|
pub(crate) chain: Box<dyn Iterator<Item = Arc<dyn Middleware + Send + Sync + 'static>>>,
|
||||||
impl<'a> MiddlewareNext<'a> {
|
pub(crate) request_fn: Box<dyn FnOnce(Request) -> Result<Response, Error> + 'a>,
|
||||||
pub(crate) fn new(n: Next<'a>) -> Self {
|
|
||||||
MiddlewareNext(n)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) enum Next<'a> {
|
|
||||||
/// Chained middleware. The Box around the next MiddlewareNext is to break the recursive datatype.
|
|
||||||
Chain(Arc<dyn Middleware>, Box<MiddlewareNext<'a>>),
|
|
||||||
/// End of the middleware chain doing the actual request invocation.
|
|
||||||
End(Box<dyn FnOnce(Request) -> Result<Response, Error> + 'a>),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> MiddlewareNext<'a> {
|
impl<'a> MiddlewareNext<'a> {
|
||||||
/// Continue the middleware chain by providing (a possibly amended) [`Request`].
|
/// Continue the middleware chain by providing (a possibly amended) [`Request`].
|
||||||
pub fn handle(self, request: Request) -> Result<Response, Error> {
|
pub fn handle(mut self, request: Request) -> Result<Response, Error> {
|
||||||
match self.0 {
|
if let Some(step) = self.chain.next() {
|
||||||
Next::Chain(mw, next) => mw.handle(request, *next),
|
step.handle(request, self)
|
||||||
Next::End(request_fn) => request_fn(request),
|
} else {
|
||||||
|
(self.request_fn)(request)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use url::{form_urlencoded, ParseError, Url};
|
|||||||
|
|
||||||
use crate::body::Payload;
|
use crate::body::Payload;
|
||||||
use crate::header::{self, Header};
|
use crate::header::{self, Header};
|
||||||
use crate::middleware::{MiddlewareNext, Next};
|
use crate::middleware::MiddlewareNext;
|
||||||
use crate::unit::{self, Unit};
|
use crate::unit::{self, Unit};
|
||||||
use crate::Response;
|
use crate::Response;
|
||||||
use crate::{agent::Agent, error::Error};
|
use crate::{agent::Agent, error::Error};
|
||||||
@@ -118,8 +118,6 @@ impl Request {
|
|||||||
#[cfg(any(feature = "gzip", feature = "brotli"))]
|
#[cfg(any(feature = "gzip", feature = "brotli"))]
|
||||||
self.add_accept_encoding();
|
self.add_accept_encoding();
|
||||||
|
|
||||||
let agent = &self.agent;
|
|
||||||
|
|
||||||
let deadline = match self.timeout.or(self.agent.config.timeout) {
|
let deadline = match self.timeout.or(self.agent.config.timeout) {
|
||||||
None => None,
|
None => None,
|
||||||
Some(timeout) => {
|
Some(timeout) => {
|
||||||
@@ -142,20 +140,17 @@ impl Request {
|
|||||||
unit::connect(unit, true, reader).map_err(|e| e.url(url.clone()))
|
unit::connect(unit, true, reader).map_err(|e| e.url(url.clone()))
|
||||||
};
|
};
|
||||||
|
|
||||||
let response = if !agent.state.middleware.is_empty() {
|
let response = if !self.agent.state.middleware.is_empty() {
|
||||||
// This clone is quite cheap since either we are cloning a Vec<Arc<dyn Middleware>>.
|
let middleware = self.agent.state.middleware.clone();
|
||||||
let middleware = agent.state.middleware.clone();
|
|
||||||
|
|
||||||
// The request_fn is the final target in the middleware chain doing the actual invocation.
|
let chain = Box::new(middleware.into_iter());
|
||||||
let mut chain = MiddlewareNext::new(Next::End(Box::new(request_fn)));
|
|
||||||
|
|
||||||
// Build middleware in reverse order.
|
let request_fn = Box::new(request_fn);
|
||||||
for mw in middleware.into_iter().rev() {
|
|
||||||
chain = MiddlewareNext::new(Next::Chain(mw, Box::new(chain)));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run middleware chain
|
let next = MiddlewareNext { chain, request_fn };
|
||||||
chain.handle(self)?
|
|
||||||
|
// // Run middleware chain
|
||||||
|
next.handle(self)?
|
||||||
} else {
|
} else {
|
||||||
// Run the request_fn without any further indirection.
|
// Run the request_fn without any further indirection.
|
||||||
request_fn(self)?
|
request_fn(self)?
|
||||||
|
|||||||
Reference in New Issue
Block a user