service_toolkit/
server.rs

1use axum_server::tls_rustls::RustlsConfig;
2use axum_server::HttpConfig;
3use hyper::server::accept::Accept;
4use itertools::Itertools;
5use rustls::server::AllowAnyAuthenticatedClient;
6use rustls::Certificate;
7use rustls::PrivateKey;
8use rustls::RootCertStore;
9use rustls::ServerConfig;
10use rustls_pemfile::certs;
11use rustls_pemfile::read_one;
12use rustls_pemfile::Item;
13use std::iter;
14use std::net::Ipv4Addr;
15use std::net::SocketAddr;
16use std::path::Path;
17use std::sync::Arc;
18use tokio::fs::remove_file;
19use tokio::fs::set_permissions;
20
21pub struct TlsCfg {
22  // These should be in the PEM format.
23  pub cert: Vec<u8>,
24  pub key: Vec<u8>,
25  // If set, mutual TLS will be enabled, and clients must send a valid certificate.
26  pub ca: Option<Vec<u8>>,
27}
28
29#[cfg(unix)]
30pub async fn build_unix_socket_server(
31  path: &Path,
32  mode: u32,
33) -> hyper::server::Builder<impl Accept<Conn = tokio::net::UnixStream, Error = std::io::Error>> {
34  use std::os::unix::fs::PermissionsExt;
35  use tokio::net::UnixListener;
36  use tokio_stream::wrappers::UnixListenerStream;
37
38  let _ = remove_file(path).await;
39  let unix_listener = UnixListener::bind(path).expect("failed to bind UNIX socket");
40  let stream = UnixListenerStream::new(unix_listener);
41  let acceptor = hyper::server::accept::from_stream(stream);
42  set_permissions(path, PermissionsExt::from_mode(mode))
43    .await
44    .unwrap();
45  axum::Server::builder(acceptor)
46}
47
48pub fn build_port_server(
49  interface: Ipv4Addr,
50  port: u16,
51) -> hyper::server::Builder<hyper::server::conn::AddrIncoming> {
52  let addr = SocketAddr::from((interface, port));
53  axum::Server::bind(&addr)
54}
55
56pub fn build_port_server_with_tls(
57  interface: Ipv4Addr,
58  port: u16,
59  tls: &TlsCfg,
60) -> axum_server::Server<axum_server::tls_rustls::RustlsAcceptor> {
61  fn priv_keys(p: &[u8]) -> Vec<Vec<u8>> {
62    let mut keys = Vec::new();
63    // WARNING: This must not be inlined, as that would reset the cursor endlessly.
64    let mut buf = p;
65    for item in iter::from_fn(|| read_one(&mut buf).transpose()) {
66      match item.expect(&format!("read item from {p:?}")) {
67        Item::ECKey(k) | Item::PKCS8Key(k) | Item::RSAKey(k) => keys.push(k),
68        _ => {}
69      };
70    }
71    keys
72  }
73
74  let tls_config = ServerConfig::builder().with_safe_defaults();
75
76  let tls_config = match &tls.ca {
77    Some(ca) => {
78      let mut roots = RootCertStore::empty();
79      for cert in certs(&mut ca.as_slice()).expect("read SSL CA PEM file certificates") {
80        roots
81          .add(&Certificate(cert))
82          .expect("add SSL CA certificate");
83      }
84      tls_config.with_client_cert_verifier(AllowAnyAuthenticatedClient::new(roots).boxed())
85    }
86    None => tls_config.with_no_client_auth(),
87  };
88
89  let mut tls_config = tls_config
90    .with_single_cert(
91      certs(&mut tls.cert.as_slice())
92        .expect("read certificates in SSL certificate PEM file")
93        .into_iter()
94        .map(|c| Certificate(c))
95        .collect_vec(),
96      PrivateKey(
97        priv_keys(&tls.key)
98          .pop()
99          .expect("no private key in SSL private key PEM file"),
100      ),
101    )
102    .expect("build SSL");
103
104  // https://github.com/programatik29/axum-server/blob/86bc6e7311959285ff00815843a8d702affe51d9/src/tls_rustls/mod.rs#L278C7-L278C7
105  tls_config.alpn_protocols = vec![b"h2".to_vec(), b"http/1.1".to_vec()];
106
107  let addr = SocketAddr::from((interface, port));
108  axum_server::bind_rustls(addr, RustlsConfig::from_config(Arc::new(tls_config))).http_config(
109    // These larger values make a significant performance improvement over long fat pipes.
110    HttpConfig::new()
111      .http2_initial_connection_window_size(1024 * 1024 * 1024)
112      .http2_initial_stream_window_size(1024 * 1024 * 1024)
113      .http2_max_frame_size(16777215) // This is the maximum supported: https://github.com/hyperium/h2/blob/633116ef68b4e7b5c4c5699fb5d10b58ef5818ac/src/frame/settings.rs#L53C11-L53C29.
114      .http2_max_pending_accept_reset_streams(2048)
115      .http2_max_send_buf_size(1024 * 1024 * 64)
116      .build(),
117  )
118}