composable_tower_http/extension/
service.rs

1use std::{
2    future::Future,
3    pin::Pin,
4    task::{Context, Poll},
5};
6
7use http::Request;
8use tower::Service;
9
10use crate::extract::{Extractor, SealedExtracted};
11
12#[derive(Debug, Clone)]
13pub struct ExtensionService<S, Ex> {
14    service: S,
15    extractor: Ex,
16}
17
18impl<S, Ex> ExtensionService<S, Ex> {
19    pub fn new(service: S, extractor: Ex) -> Self {
20        Self { service, extractor }
21    }
22}
23
24impl<S, Ex, B> Service<Request<B>> for ExtensionService<S, Ex>
25where
26    Ex: Extractor + Clone + Send + 'static,
27    S: Service<Request<B>> + Clone + Send + 'static,
28    S::Future: Send,
29    S::Response: From<Ex::Error>,
30    B: Send + 'static,
31{
32    type Response = S::Response;
33    type Error = S::Error;
34    type Future = Pin<Box<dyn Future<Output = Result<S::Response, S::Error>> + Send>>;
35
36    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
37        self.service.poll_ready(cx)
38    }
39
40    fn call(&mut self, mut request: Request<B>) -> Self::Future {
41        let mut service = self.service.clone();
42        let extractor = self.extractor.clone();
43
44        Box::pin(async move {
45            let headers = request.headers();
46
47            let extracted = match extractor.extract(headers).await {
48                Ok(extracted) => extracted,
49                Err(err) => return Ok(From::from(err)),
50            };
51
52            request.extensions_mut().insert(SealedExtracted(extracted));
53
54            service.call(request).await
55        })
56    }
57}