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