routerify_unixsocket/
lib.rs

1//! Routerify <> Hyperlocal
2//! Serve unix sockets with routerify
3//!
4//! Basic usage works by replacing [`RouterService`](routerify::RouterService) with [`UnixRouterService`], which adapts the
5//! request in order to be compatible with [`RequestService`](routerify::RequestService).
6//!
7//! Since routerify requires an IP [`SocketAddr`](std::net::SocketAddr), the loopback address `127.0.0.1` with port 0 is used as a placeholder.
8//! In order to access the unix socket's peer address and peer credential, the [`UnixRequestExt`] extension traits adds methods to the request object.
9//!
10//! # Example
11//! ```no_run
12//! use hyper::{Body, Response, Server};
13//! use hyperlocal::UnixServerExt;
14//! use routerify::{Error, Router};
15//! use routerify_unixsocket::{UnixRequestExt, UnixRouterService};
16//! use std::{fs, path::Path};
17//!
18//! #[tokio::main]
19//! async fn main() {
20//!     let path = Path::new("/tmp/hyperlocal.sock");
21//!     if path.exists() {
22//!         fs::remove_file(path).unwrap();
23//!     }
24//!
25//!     let router: Router<Body, Error> = Router::builder()
26//!         .get("/", |req| async move {
27//!             let s = format!("You are: {:?}", req.unix_peer_cred());
28//!             Ok(Response::new(Body::from(s)))
29//!         })
30//!         .build()
31//!         .unwrap();
32//!
33//!     let service = UnixRouterService::new(router).unwrap();
34//!     Server::bind_unix(path)
35//!         .unwrap()
36//!         .serve(service)
37//!         .await
38//!         .unwrap()
39//! }
40//! ```
41
42mod router_service;
43pub use router_service::UnixRouterService;
44
45mod ext;
46pub use ext::UnixRequestExt;
47
48mod request_meta;
49
50#[cfg(test)]
51mod tests {
52    use super::*;
53    use futures::future::poll_fn;
54    use hyper::{Body, Method, Request, Response};
55    use routerify::{Error, Router};
56    use std::task::Poll;
57    use tokio::net::UnixStream;
58    use tower::Service;
59
60    #[tokio::test]
61    pub async fn unixsocket() {
62        const RESPONSE_TEXT: &str = "Hello world!";
63
64        let mut router_service = {
65            let router: Router<Body, Error> = Router::builder()
66                .get("/", |_req| async move {
67                    Ok(Response::new(Body::from(RESPONSE_TEXT)))
68                })
69                .build()
70                .unwrap();
71
72            UnixRouterService::new(router).unwrap()
73        };
74
75        poll_fn(|ctx| -> Poll<_> { router_service.poll_ready(ctx) })
76            .await
77            .expect("router service is not ready");
78
79        let (_, server) = UnixStream::pair().unwrap();
80
81        let mut service = router_service.call(&server).await.unwrap();
82        poll_fn(|ctx| -> Poll<_> { service.poll_ready(ctx) })
83            .await
84            .expect("request service is not ready");
85
86        let req = Request::builder()
87            .method(Method::GET)
88            .uri("/")
89            .body(hyper::Body::empty())
90            .unwrap();
91
92        let resp: Response<hyper::body::Body> = service.call(req).await.unwrap();
93        let body = resp.into_body();
94        let body = String::from_utf8(hyper::body::to_bytes(body).await.unwrap().to_vec()).unwrap();
95        assert_eq!(RESPONSE_TEXT, body);
96    }
97}