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}