satex_layer/set_prefix/
mod.rs1#![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}