routerify_unixsocket/
router_service.rs

1use crate::request_meta::RequestMeta;
2use hyper::{body::HttpBody, service::Service};
3use routerify::{RequestServiceBuilder, Router};
4use std::{
5    convert::Infallible,
6    future::{ready, Ready},
7    net::{Ipv4Addr, SocketAddr, SocketAddrV4},
8    task::{Context, Poll},
9};
10use tower::util::{BoxService, ServiceExt};
11
12/// A [`Service`](hyper::service::Service) to process incoming requests.
13/// This is adapted from routerify's [`RouterService`](routerify::RouterService) in order to support handling the [`tokio::net::UnixStream`]
14/// instance passed by [`hyperlocal`]
15///
16/// This `RouterService<B, E>` type accepts two type parameters: `B` and `E`.
17///
18/// * The `B` represents the response body type which will be used by route handlers and the middlewares and this body type must implement
19///   the [`HttpBody`](hyper::body::HttpBody) trait. For an instance, `B` could be [`hyper::Body`](hyper::body::Body)
20///   type.
21/// * The `E` represents any error type which will be used by route handlers and the middlewares. This error type must implement the [`std::error::Error`].
22#[derive(Debug)]
23pub struct UnixRouterService<B, E>
24where
25    B: HttpBody + Send + Sync + 'static,
26{
27    builder: RequestServiceBuilder<B, E>,
28}
29
30impl<
31        B: HttpBody + Send + Sync + 'static,
32        E: Into<Box<dyn std::error::Error + Send + Sync>> + 'static,
33    > UnixRouterService<B, E>
34{
35    /// Creates a new service with the provided router and it's ready to be used with the hyper [`serve`](hyper::server::Builder::.serve)
36    /// method.
37    pub fn new(router: Router<B, E>) -> routerify::Result<UnixRouterService<B, E>> {
38        let builder = RequestServiceBuilder::new(router)?;
39        Ok(UnixRouterService { builder })
40    }
41}
42
43impl<
44        B: HttpBody + Send + Sync + 'static,
45        E: Into<Box<dyn std::error::Error + Send + Sync>> + 'static,
46    > Service<&tokio::net::UnixStream> for UnixRouterService<B, E>
47{
48    type Response =
49        BoxService<hyper::Request<hyper::Body>, hyper::Response<B>, routerify::RouteError>;
50    type Error = Infallible;
51    type Future = Ready<Result<Self::Response, Self::Error>>;
52
53    fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
54        Poll::Ready(Ok(()))
55    }
56
57    fn call(&mut self, conn: &tokio::net::UnixStream) -> Self::Future {
58        let loopback = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 0));
59        let meta = RequestMeta::new(conn);
60
61        let req_service = self.builder.build(loopback).map_request(
62            move |mut req: hyper::Request<hyper::Body>| {
63                let ext = req.extensions_mut();
64                if ext.get_mut::<RequestMeta>().is_none() {
65                    ext.insert(meta.clone());
66                }
67                req
68            },
69        );
70        ready(Ok(BoxService::new(req_service)))
71    }
72}