composable_tower_http/extension/
service.rs1use 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}