credence_lib/server/
server.rs

1use super::{
2    super::{configuration::*, middleware::*},
3    routers::*,
4    site::*,
5};
6
7use {
8    ::axum::middleware::*,
9    axum_server::*,
10    bytestring::*,
11    kutil_http::{axum::*, tls::*},
12    kutil_std::{future::*, string::*},
13    std::net::*,
14};
15
16//
17// Server
18//
19
20/// Credence server.
21///
22/// Listens on a single [SocketAddr] with one or more [Router].
23#[derive(Clone, Debug)]
24pub struct Server {
25    /// Hosts.
26    pub hosts: Vec<ByteString>,
27
28    /// TLS container.
29    pub tls: TlsContainer,
30
31    /// Host router.
32    pub host_router: HostRouter,
33}
34
35impl Server {
36    /// Constructor.
37    pub fn new() -> Self {
38        Self { hosts: Vec::new(), tls: TlsContainer::default(), host_router: HostRouter::default() }
39    }
40
41    /// Add the [Site] for all configured hosts.
42    ///
43    /// Also adds TLS keys, if configured, to the [TlsContainer].
44    pub fn add_router(&mut self, site: &Site, tcp_port: u16, port: &Port) -> Result<(), ConfigurationError> {
45        if port.hosts.is_empty() {
46            let host = ByteString::new();
47
48            // Add socket middleware
49            let router = site.router.clone().layer(map_request_with_state(
50                SocketMiddleware::new(Socket::new(tcp_port, false, host.clone())),
51                SocketMiddleware::function,
52            ));
53
54            self.host_router.add(host.clone(), router);
55            self.host_router.fallback_host = Some(host);
56
57            return Ok(());
58        }
59
60        let is_tls = port.is_tls();
61
62        for host in &port.hosts {
63            if self.hosts.contains(&host.host) {
64                return Err(format!("host used more than once for port {}: {}", tcp_port, host.host).into());
65            }
66
67            self.hosts.push(host.host.clone());
68
69            let host_and_optional_port = match tcp_port {
70                80 | 443 => host.host.clone(),
71                _ => format!("{}:{}", host.host, tcp_port).into(),
72            };
73
74            if let Some(to_tcp_port) = host.redirect_to {
75                match site.configuration.ports.get(&to_tcp_port) {
76                    Some(to_port) => {
77                        let mut has_to_host = false;
78                        for to_host in &to_port.hosts {
79                            if to_host.host == host.host {
80                                has_to_host = true;
81                                break;
82                            }
83                        }
84
85                        if !has_to_host {
86                            return Err(format!(
87                                "port {} host {:?} `redirect-to` port {} does not have the host",
88                                tcp_port, host.host, to_tcp_port
89                            )
90                            .into());
91                        }
92
93                        let router = new_redirecting_router(to_port.is_tls(), host.host.clone(), to_tcp_port);
94                        self.host_router.add(host_and_optional_port, router);
95                    }
96
97                    None => {
98                        return Err(format!(
99                            "port {} host {:?} `redirect-to` port is undefined: {}",
100                            tcp_port, host.host, to_tcp_port
101                        )
102                        .into());
103                    }
104                }
105            } else {
106                // Add socket middleware
107                let router = site.router.clone().layer(map_request_with_state(
108                    SocketMiddleware::new(Socket::new(tcp_port, is_tls, host.host.clone())),
109                    SocketMiddleware::function,
110                ));
111
112                self.host_router.add(host_and_optional_port, router);
113            }
114
115            if is_tls {
116                if let Some(key) = &host.key {
117                    let (certificates, private_key) = key.to_bytes()?;
118                    self.tls.add_key_from_pem(host.host.clone(), &certificates, &private_key)?;
119                } else if let Some(acme) = &host.acme {
120                    self.tls.add_resolver_from_acme(acme.provider(host.host.clone()))?;
121                } else {
122                    return Err(format!("listener {:?} has both TLS and non-TLS hosts", port.name).into());
123                }
124            }
125        }
126
127        Ok(())
128    }
129
130    /// Create a server task on a socket.
131    pub fn start(
132        self,
133        socket_address: SocketAddr,
134        server_handle: &Handle,
135    ) -> Result<Option<CapturedIoTask>, ConfigurationError> {
136        let router = match self.host_router.into_router() {
137            Some(router) => router,
138            None => return Ok(None),
139        };
140
141        if self.tls.is_empty() {
142            tracing::info!("starting server: {}{}", socket_address, display_hosts(&self.hosts));
143
144            let server = bind(socket_address).handle(server_handle.clone());
145            let task = server.serve(router.into_make_service());
146            return Ok(Some(Box::pin(task)));
147        } else {
148            tracing::info!("starting server: {} with TLS{}", socket_address, display_hosts(&self.hosts));
149
150            let acceptor = self.tls.axum_acceptor()?;
151            let server = bind(socket_address).handle(server_handle.clone()).acceptor(acceptor);
152            let task = server.serve(router.into_make_service());
153            return Ok(Some(Box::pin(task)));
154        }
155    }
156}
157
158fn display_hosts(hosts: &Vec<ByteString>) -> String {
159    if hosts.is_empty() {
160        "".into()
161    } else {
162        let hosts: Vec<_> = hosts.iter().map(|host| format!("{:?}", host)).collect();
163        String::from(" for ") + &hosts.join_conjunction("and")
164    }
165}