satex_layer/set_prefix/
mod.rs

1#![doc = include_str!("../../docs/set_prefix.md")]
2
3mod layer;
4mod make;
5pub use layer::*;
6pub use make::*;
7
8use futures::future::LocalBoxFuture;
9use futures::{FutureExt, TryFutureExt};
10use http::{Request, Uri};
11use satex_core::{BoxError, Error};
12use std::future::ready;
13use std::str::FromStr;
14use std::sync::Arc;
15use std::task::{Context, Poll};
16use tower::Service;
17
18#[derive(Debug, Clone)]
19pub struct SetPrefix<S> {
20    inner: S,
21    prefix: Arc<str>,
22}
23
24impl<S> SetPrefix<S> {
25    pub fn new(inner: S, prefix: Arc<str>) -> Self {
26        Self { prefix, inner }
27    }
28}
29
30impl<S, ReqBody> Service<Request<ReqBody>> for SetPrefix<S>
31where
32    S: Service<Request<ReqBody>>,
33    S::Error: Into<BoxError>,
34    S::Future: 'static,
35    S::Response: Send + 'static,
36{
37    type Response = S::Response;
38    type Error = Error;
39    type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>;
40
41    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
42        self.inner.poll_ready(cx).map_err(|e| Error::new(e.into()))
43    }
44
45    fn call(&mut self, mut request: Request<ReqBody>) -> Self::Future {
46        let uri = request.uri();
47        let path_and_query = match uri.path_and_query() {
48            Some(path_and_query) => {
49                let path_and_query = path_and_query.as_str();
50                if path_and_query == "/" {
51                    self.prefix.to_string()
52                } else {
53                    format!("{}{}", self.prefix.as_ref(), path_and_query)
54                }
55            }
56            None => self.prefix.to_string(),
57        };
58
59        match Uri::from_str(&path_and_query) {
60            Ok(uri) => {
61                *request.uri_mut() = uri;
62                self.inner
63                    .call(request)
64                    .map_err(|e| Error::new(e.into()))
65                    .boxed_local()
66            }
67            Err(e) => ready(Err(Error::new(e))).boxed(),
68        }
69    }
70}