1mod acme;
2mod config;
3mod handler;
4mod listener_handler_communication;
5mod listeners;
6mod request_handler;
7mod runtime;
8mod setup;
9mod util;
10
11use std::collections::{HashMap, HashSet};
12use std::error::Error;
13use std::net::{IpAddr, Ipv6Addr, SocketAddr};
14use std::path::Path;
15use std::sync::{Arc, LazyLock, Mutex, OnceLock};
16use std::thread;
17use std::time::Duration;
18
19use arc_swap::ArcSwap;
20use async_channel::{Receiver, Sender};
21use clap::Parser;
22use ferron_common::logging::{ErrorLogger, LogMessage};
23use ferron_common::{get_entry, get_value};
24use ferron_load_modules::{obtain_module_loaders, obtain_observability_backend_loaders};
25use human_panic::{setup_panic, Metadata};
26use mimalloc::MiMalloc;
27use rustls::server::{ResolvesServerCert, WebPkiClientVerifier};
28use rustls::{RootCertStore, ServerConfig};
29use rustls_native_certs::load_native_certs;
30use shadow_rs::shadow;
31use tempfile::NamedTempFile;
32use tokio_util::sync::CancellationToken;
33
34use crate::acme::{
35 check_certificate_validity_or_install_cached, convert_on_demand_config, get_cached_domains, ACME_TLS_ALPN_NAME,
36};
37use crate::config::adapters::ConfigurationAdapter;
38use crate::config::processing::{
39 load_modules, merge_duplicates, premerge_configuration, remove_and_add_global_configuration,
40};
41use crate::config::ServerConfigurations;
42use crate::handler::{create_http_handler, ReloadableHandlerData};
43use crate::listener_handler_communication::ConnectionData;
44use crate::listeners::{create_quic_listener, create_tcp_listener};
45use crate::setup::acme::background_acme_task;
46use crate::setup::cli::{Command, ConfigAdapter, FerronArgs, LogOutput};
47use crate::setup::tls::{
48 handle_automatic_tls, handle_manual_tls, handle_nonencrypted_ports, manual_tls_entry, read_default_port,
49 resolve_sni_hostname, should_skip_server, TlsBuildContext,
50};
51use crate::setup::tls_single::{init_crypto_provider, set_tls_version};
52use crate::util::{load_certs, MultiCancel};
53
54#[global_allocator]
56static GLOBAL: MiMalloc = MiMalloc;
57
58shadow!(build);
59
60type LazyLockArc<T> = LazyLock<Arc<T>>;
61type LazyLockMutex<T> = LazyLockArc<Mutex<T>>;
62
63static LISTENER_HANDLER_CHANNEL: LazyLockArc<(Sender<ConnectionData>, Receiver<ConnectionData>)> =
64 LazyLock::new(|| Arc::new(async_channel::unbounded()));
65static TCP_LISTENERS: LazyLockMutex<HashMap<SocketAddr, CancellationToken>> =
66 LazyLock::new(|| Arc::new(Mutex::new(HashMap::new())));
67#[allow(clippy::type_complexity)]
68static QUIC_LISTENERS: LazyLockMutex<HashMap<SocketAddr, (CancellationToken, Sender<Arc<ServerConfig>>)>> =
69 LazyLock::new(|| Arc::new(Mutex::new(HashMap::new())));
70static HANDLERS: LazyLockMutex<Vec<(CancellationToken, Sender<()>)>> =
71 LazyLock::new(|| Arc::new(Mutex::new(Vec::new())));
72static SERVER_CONFIG_ARCSWAP: OnceLock<Arc<ArcSwap<ReloadableHandlerData>>> = OnceLock::new();
73static URING_ENABLED: LazyLockMutex<Option<bool>> = LazyLock::new(|| Arc::new(Mutex::new(None)));
74static LISTENER_LOGGING_CHANNEL: LazyLockArc<(Sender<LogMessage>, Receiver<LogMessage>)> =
75 LazyLock::new(|| Arc::new(async_channel::unbounded()));
76
77fn handle_shutdown_signals(runtime: &tokio::runtime::Runtime) -> bool {
79 runtime.block_on(async move {
80 #[cfg(unix)]
81 let configuration_reload_future = async {
82 if let Ok(mut signal) = tokio::signal::unix::signal(tokio::signal::unix::SignalKind::hangup()) {
83 signal.recv().await
84 } else {
85 futures_util::future::pending().await
86 }
87 };
88 #[cfg(not(unix))]
89 let configuration_reload_future = async { futures_util::future::pending::<Option<()>>().await };
90
91 let shutdown_future = async {
92 if tokio::signal::ctrl_c().await.is_err() {
93 futures_util::future::pending().await
94 }
95 };
96
97 let continue_running = tokio::select! {
98 _ = shutdown_future => {
99 false
100 }
101 _ = configuration_reload_future => {
102 true
103 }
104 };
105 continue_running
106 })
107}
108
109fn before_starting_server(
111 args: FerronArgs,
112 configuration_adapters: HashMap<String, Box<dyn ConfigurationAdapter + Send + Sync>>,
113) -> Result<(), Box<dyn Error + Send + Sync>> {
114 let temp_config_file: NamedTempFile;
117 let configuration_path: &Path = if let Some(config_string) = args.config_string.as_ref() {
119 temp_config_file = NamedTempFile::new()?;
120 std::fs::write(temp_config_file.path(), config_string)?;
121 temp_config_file.path()
122 } else if let Some(command) = args.command.as_ref() {
123 match command {
124 Command::Serve(http_serve_args) => {
125 let mut config_string = format!(
126 "* {{\n listen_ip \"{}\"\n default_http_port {}",
127 http_serve_args.listen_ip, http_serve_args.port
128 );
129 if !http_serve_args.credential.is_empty() {
130 let mut users = Vec::<String>::new();
131 for credential in http_serve_args.credential.iter() {
132 let (user, hashed_password) = credential
133 .rsplit_once(':')
134 .ok_or(anyhow::anyhow!("Invalid credential format: {credential}"))?;
135 users.push(user.to_owned());
136 config_string.push_str(
137 format!(
138 "\n user \"{}\" \"{}\"",
139 user.escape_default(),
140 hashed_password.escape_default()
141 )
142 .as_str(),
143 );
144 }
145 if http_serve_args.forward_proxy {
146 config_string.push_str(
147 format!(
148 "\n forward_proxy_auth users=\"{}\" brute_protection=#{}",
149 users.join(",").escape_default(),
150 http_serve_args.disable_brute_protection
151 )
152 .as_str(),
153 );
154 } else {
155 config_string.push_str(
156 format!(
157 "\n status 401 users=\"{}\" brute_protection=#{}",
158 users.join(",").escape_default(),
159 http_serve_args.disable_brute_protection
160 )
161 .as_str(),
162 );
163 }
164 }
165 match http_serve_args.log {
166 LogOutput::Stdout => {
167 config_string.push_str("\n log_stdout");
168 }
169 LogOutput::Stderr => {
170 config_string.push_str("\n log_stderr");
171 }
172 LogOutput::Off => {}
173 }
174 match http_serve_args.error_log {
175 LogOutput::Stdout => {
176 config_string.push_str("\n error_log_stdout");
177 }
178 LogOutput::Stderr => {
179 config_string.push_str("\n error_log_stderr");
180 }
181 LogOutput::Off => {}
182 }
183 if http_serve_args.forward_proxy {
184 config_string.push_str("\n forward_proxy");
185 } else {
186 config_string.push_str(
187 format!(
188 "\n root \"{}\"",
189 http_serve_args.root.to_string_lossy().into_owned().escape_default()
190 )
191 .as_str(),
192 );
193 config_string.push_str("\n directory_listing #true");
194 }
195 config_string.push_str("\n}\n");
196 temp_config_file = NamedTempFile::new()?;
197 std::fs::write(temp_config_file.path(), config_string)?;
198 temp_config_file.path()
199 }
200 }
201 } else {
202 args.config.as_path()
203 };
204 let configuration_adapter: &str = if let Some(config_adapter) = args.config_adapter.as_ref() {
205 match config_adapter {
206 ConfigAdapter::Kdl => "kdl",
207 #[cfg(feature = "config-yaml-legacy")]
208 ConfigAdapter::YamlLegacy => "yaml-legacy",
209 #[cfg(feature = "config-docker-auto")]
210 ConfigAdapter::DockerAuto => "docker-auto",
211 }
212 } else if args.config_string.is_some() {
213 "kdl"
215 } else {
216 determine_default_configuration_adapter(configuration_path)
217 };
218
219 let configuration_adapter = configuration_adapters
221 .get(configuration_adapter)
222 .ok_or(anyhow::anyhow!(
223 "The \"{}\" configuration adapter isn't supported",
224 configuration_adapter
225 ))?;
226
227 let available_parallelism = thread::available_parallelism()?.get();
229
230 let mut first_startup = true;
232
233 let mut background_cancel_token: CancellationToken = CancellationToken::new();
235
236 let mut ocsp_cancel_token: CancellationToken = CancellationToken::new();
238
239 let secondary_runtime = tokio::runtime::Builder::new_multi_thread()
241 .worker_threads(match available_parallelism / 2 {
242 0 => 1,
243 non_zero => non_zero,
244 })
245 .thread_name("Secondary runtime")
246 .enable_all()
247 .build()?;
248
249 loop {
250 let mut module_loaders = obtain_module_loaders();
252
253 let mut observability_backend_loaders = obtain_observability_backend_loaders();
255
256 let configs_to_process = configuration_adapter.load_configuration(configuration_path)?;
258
259 let configs_to_process = merge_duplicates(configs_to_process);
261 let configs_to_process = remove_and_add_global_configuration(configs_to_process);
262 let configs_to_process = premerge_configuration(configs_to_process);
263 let (configs_to_process, first_module_error, unused_properties) = load_modules(
264 configs_to_process,
265 &mut module_loaders,
266 &mut observability_backend_loaders,
267 &secondary_runtime,
268 );
269
270 let server_configurations = Arc::new(ServerConfigurations::new(configs_to_process));
272
273 let global_configuration = server_configurations.find_global_configuration();
274 let global_configuration_clone = global_configuration.clone();
275
276 let secondary_runtime_ref = &secondary_runtime;
277
278 let background_cancel_token_ref = &mut background_cancel_token;
280 let ocsp_cancel_token_ref = &mut ocsp_cancel_token;
281
282 let execute_rest = move || {
284 if let Some(first_module_error) = first_module_error {
285 Err(first_module_error)?;
287 }
288
289 for unused_property in unused_properties {
291 for logging_tx in global_configuration
292 .as_ref()
293 .map_or(&vec![], |c| &c.observability.log_channels)
294 {
295 logging_tx
296 .send_blocking(LogMessage::new(
297 format!("Unused configuration property detected: \"{unused_property}\""),
298 true,
299 ))
300 .unwrap_or_default();
301 }
302 }
303
304 let crypto_provider = init_crypto_provider(global_configuration.as_deref())?;
306
307 if crypto_provider.clone().install_default().is_err() && first_startup {
309 Err(anyhow::anyhow!("Cannot install a process-wide cryptography provider"))?;
310 }
311
312 let crypto_provider = Arc::new(crypto_provider);
313
314 let tls_config_builder_wants_versions = ServerConfig::builder_with_provider(crypto_provider.clone());
316 let tls_config_builder_wants_verifier =
317 set_tls_version(tls_config_builder_wants_versions, global_configuration.as_deref())?;
318
319 let tls_config_builder_wants_server_cert = if let Some(client_cert_path) = global_configuration
320 .as_deref()
321 .and_then(|c| get_value!("tls_client_certificate", c))
322 .and_then(|v| v.as_str())
323 {
324 let mut roots = RootCertStore::empty();
325 let client_certificate_cas = load_certs(client_cert_path)?;
326 for cert in client_certificate_cas {
327 roots.add(cert)?;
328 }
329 tls_config_builder_wants_verifier
330 .with_client_cert_verifier(WebPkiClientVerifier::builder(Arc::new(roots)).build()?)
331 } else if global_configuration
332 .as_deref()
333 .and_then(|c| get_value!("tls_client_certificate", c))
334 .and_then(|v| v.as_bool())
335 .unwrap_or(false)
336 {
337 let roots = (|| {
338 let certs_result = load_native_certs();
339 if !certs_result.errors.is_empty() {
340 return None;
341 }
342 let certs = certs_result.certs;
343
344 let mut roots = RootCertStore::empty();
345 for cert in certs {
346 if roots.add(cert).is_err() {
347 return None;
348 }
349 }
350
351 Some(roots)
352 })()
353 .unwrap_or(RootCertStore {
354 roots: webpki_roots::TLS_SERVER_ROOTS.to_vec(),
355 });
356
357 tls_config_builder_wants_verifier
358 .with_client_cert_verifier(WebPkiClientVerifier::builder(Arc::new(roots)).build()?)
359 } else {
360 tls_config_builder_wants_verifier.with_no_client_auth()
361 };
362
363 let enable_proxy_protocol = global_configuration
364 .as_ref()
365 .and_then(|c| get_value!("protocol_proxy", c))
366 .and_then(|v| v.as_bool())
367 .unwrap_or(false);
368 let protocols = global_configuration
369 .as_ref()
370 .and_then(|c| get_entry!("protocols", c))
371 .map(|e| e.values.iter().filter_map(|v| v.as_str()).collect::<Vec<_>>())
372 .unwrap_or(vec!["h1", "h2"]);
373
374 if enable_proxy_protocol && protocols.contains(&"h3") {
375 Err(anyhow::anyhow!("PROXY protocol isn't supported with HTTP/3"))?
376 }
377
378 let default_http_port = read_default_port(global_configuration.as_deref(), false);
379 let default_https_port = read_default_port(global_configuration.as_deref(), true);
380
381 let mut tls_build_ctx = TlsBuildContext::default();
382 let memory_acme_account_cache_data: Arc<tokio::sync::RwLock<HashMap<String, Vec<u8>>>> = Default::default();
383 let mut invalid_wildcard_domains: HashSet<String> = HashSet::new();
384
385 for server in &server_configurations.host_configs {
387 let hostname = server.filters.hostname.as_deref();
388 if let Some(hostname) = hostname {
389 if hostname.contains("*.") && (hostname == "*." || !hostname.starts_with("*.")) {
390 invalid_wildcard_domains.insert(hostname.to_string());
391 }
392 }
393
394 if should_skip_server(server) {
395 continue;
396 }
397
398 let sni_hostname = resolve_sni_hostname(&server.filters);
399 let https_port = server.filters.port.or(default_https_port);
400
401 handle_nonencrypted_ports(&mut tls_build_ctx, server, default_http_port);
402
403 if let Some(https_port) = https_port {
404 let manual_tls_entry_option = manual_tls_entry(server);
405 if get_entry!("auto_tls", server)
406 .and_then(|e| e.values.first())
407 .and_then(|v| v.as_bool())
408 .unwrap_or(server.filters.port.is_none() && manual_tls_entry_option.is_none())
409 {
410 if let Some(error_log_message) = handle_automatic_tls(
411 &mut tls_build_ctx,
412 server,
413 https_port,
414 sni_hostname.clone(),
415 crypto_provider.clone(),
416 memory_acme_account_cache_data.clone(),
417 )? {
418 for logging_tx in global_configuration
419 .as_ref()
420 .map_or(&vec![], |c| &c.observability.log_channels)
421 {
422 logging_tx.send_blocking(error_log_message.clone()).unwrap_or_default();
423 }
424 } else {
425 continue;
426 }
427 }
428 if let Some((cert, key)) = manual_tls_entry(server) {
429 handle_manual_tls(
430 &mut tls_build_ctx,
431 &crypto_provider,
432 https_port,
433 sni_hostname,
434 cert,
435 key,
436 )?;
437 }
438 }
439 }
440
441 for invalid_wildcard_domain in invalid_wildcard_domains {
442 for logging_tx in global_configuration
443 .as_ref()
444 .map_or(&vec![], |c| &c.observability.log_channels)
445 {
446 logging_tx
447 .send_blocking(LogMessage::new(
448 format!(
449 "Invalid wildcard domain detected: \"{invalid_wildcard_domain}\". \
450 It should be in the form of \"*.example.com\" (that means wildcard is at the beginning)."
451 ),
452 true,
453 ))
454 .unwrap_or_default();
455 }
456 }
457
458 if !protocols.contains(&"h1") {
460 tls_build_ctx.nonencrypted_ports.clear();
461 }
462
463 for tls_port in tls_build_ctx.tls_ports.keys() {
464 if tls_build_ctx.nonencrypted_ports.contains(tls_port) {
465 tls_build_ctx.nonencrypted_ports.remove(tls_port);
466 }
467 }
468
469 ocsp_cancel_token_ref.cancel();
471 *ocsp_cancel_token_ref = CancellationToken::new();
472
473 let mut quic_tls_configs = HashMap::new();
475 let mut tls_configs = HashMap::new();
476 let mut acme_tls_alpn_01_configs = HashMap::new();
477 let certified_keys_to_preload = Arc::new(tls_build_ctx.certified_keys_to_preload);
478 for (tls_port, sni_resolver) in tls_build_ctx.tls_ports.into_iter() {
479 let enable_ocsp_stapling = global_configuration
480 .as_ref()
481 .and_then(|c| get_value!("ocsp_stapling", c))
482 .and_then(|v| v.as_bool())
483 .unwrap_or(true);
484 let resolver: Arc<dyn ResolvesServerCert> = if enable_ocsp_stapling {
485 let stapler =
488 secondary_runtime_ref.block_on(async move { ocsp_stapler::Stapler::new(Arc::new(sni_resolver)) });
489 if let Some(certified_keys_to_preload) = certified_keys_to_preload.get(&tls_port) {
490 for certified_key in certified_keys_to_preload {
491 stapler.preload(certified_key.clone());
492 }
493 }
494 let stapler_arc = Arc::new(stapler);
495
496 let stapler_arc_clone = stapler_arc.clone();
497 let ocsp_cancel_token_clone = ocsp_cancel_token_ref.clone();
498 secondary_runtime_ref.spawn(async move {
499 ocsp_cancel_token_clone.cancelled().await;
500 stapler_arc_clone.stop().await;
501 });
502
503 stapler_arc
504 } else {
505 Arc::new(sni_resolver)
506 };
507 let mut tls_config = tls_config_builder_wants_server_cert
508 .clone()
509 .with_cert_resolver(resolver);
510 if protocols.contains(&"h3") {
511 let mut quic_tls_config = tls_config.clone();
513 quic_tls_config.max_early_data_size = u32::MAX;
514 quic_tls_config.alpn_protocols.insert(0, b"h3-29".to_vec());
515 quic_tls_config.alpn_protocols.insert(0, b"h3".to_vec());
516 quic_tls_configs.insert(tls_port, Arc::new(quic_tls_config));
517 }
518 if protocols.contains(&"h1") {
519 tls_config.alpn_protocols.insert(0, b"http/1.0".to_vec());
520 tls_config.alpn_protocols.insert(0, b"http/1.1".to_vec());
521 }
522 if protocols.contains(&"h2") {
523 tls_config.alpn_protocols.insert(0, b"h2".to_vec());
524 }
525 tls_configs.insert(tls_port, Arc::new(tls_config));
526 }
527 for (tls_port, sni_resolver) in tls_build_ctx.acme_tls_alpn_01_resolvers.into_iter() {
528 let mut tls_config = tls_config_builder_wants_server_cert
529 .clone()
530 .with_cert_resolver(Arc::new(sni_resolver));
531 tls_config.alpn_protocols = vec![ACME_TLS_ALPN_NAME.to_vec()];
532 acme_tls_alpn_01_configs.insert(tls_port, Arc::new(tls_config));
533 }
534
535 let (listener_handler_tx, listener_handler_rx) = &**LISTENER_HANDLER_CHANNEL;
536 let mut tcp_listeners = TCP_LISTENERS
537 .lock()
538 .map_err(|_| anyhow::anyhow!("Can't access the TCP listeners"))?;
539 let mut quic_listeners = QUIC_LISTENERS
540 .lock()
541 .map_err(|_| anyhow::anyhow!("Can't access the QUIC listeners"))?;
542 let mut listened_socket_addresses = Vec::new();
543 let mut quic_listened_socket_addresses = Vec::new();
544 let listen_ip_addr = global_configuration
545 .as_deref()
546 .and_then(|c| get_value!("listen_ip", c))
547 .and_then(|v| v.as_str())
548 .map_or(Ok(IpAddr::V6(Ipv6Addr::UNSPECIFIED)), |a| a.parse())
549 .map_err(|_| anyhow::anyhow!("Invalid IP address to listen to"))?;
550 for (tcp_port, encrypted) in tls_build_ctx
551 .nonencrypted_ports
552 .iter()
553 .map(|p| (*p, false))
554 .chain(tls_configs.keys().map(|p| (*p, true)))
555 {
556 let socket_address = SocketAddr::new(listen_ip_addr, tcp_port);
557 listened_socket_addresses.push((socket_address, encrypted));
558 }
559 for (quic_port, quic_tls_config) in quic_tls_configs.into_iter() {
560 let socket_address = SocketAddr::new(listen_ip_addr, quic_port);
561 quic_listened_socket_addresses.push((socket_address, quic_tls_config));
562 }
563
564 let enable_uring = global_configuration
565 .as_deref()
566 .and_then(|c| get_value!("io_uring", c))
567 .and_then(|v| v.as_bool());
568 let mut uring_enabled_locked = URING_ENABLED
569 .lock()
570 .map_err(|_| anyhow::anyhow!("Can't access the enabled `io_uring` option"))?;
571 let shutdown_handlers = enable_uring != *uring_enabled_locked;
572 let mut tcp_listener_socketaddrs_to_remove = Vec::new();
573 let mut quic_listener_socketaddrs_to_remove = Vec::new();
574 for (key, value) in &*tcp_listeners {
575 if enable_uring != *uring_enabled_locked
576 || (!listened_socket_addresses.contains(&(*key, true)) && !listened_socket_addresses.contains(&(*key, false)))
577 {
578 value.cancel();
580
581 tcp_listener_socketaddrs_to_remove.push(*key);
583 }
584 }
585 for (key, value) in &*quic_listeners {
586 let mut contains = false;
587 for key2 in &quic_listened_socket_addresses {
588 if key2.0 == *key {
589 contains = true;
590 break;
591 }
592 }
593 if !contains {
594 value.0.cancel();
596
597 quic_listener_socketaddrs_to_remove.push(*key);
599 }
600 }
601 *uring_enabled_locked = enable_uring;
602 drop(uring_enabled_locked);
603
604 for key_to_remove in tcp_listener_socketaddrs_to_remove {
605 tcp_listeners.remove(&key_to_remove);
607 }
608
609 for key_to_remove in quic_listener_socketaddrs_to_remove {
610 quic_listeners.remove(&key_to_remove);
612 }
613
614 let (global_logging_tx, global_logging_rx) = &**LISTENER_LOGGING_CHANNEL;
616 let global_logger = if global_configuration
617 .as_ref()
618 .is_none_or(|c| c.observability.log_channels.is_empty())
619 {
620 None
621 } else {
622 let global_configuration_clone = global_configuration.clone();
623 secondary_runtime_ref.spawn(async move {
624 while let Ok(log_message) = global_logging_rx.recv().await {
625 for logging_tx in global_configuration_clone
626 .as_ref()
627 .map_or(&vec![], |c| &c.observability.log_channels)
628 {
629 logging_tx.send(log_message.clone()).await.unwrap_or_default();
630 }
631 }
632 });
633 Some(global_logging_tx.clone())
634 };
635
636 let (io_uring_disabled_tx, io_uring_disabled_rx) = async_channel::unbounded();
637 if let Some(global_logger) = &global_logger {
638 let global_logger = global_logger.clone();
639 secondary_runtime_ref.spawn(async move {
640 while let Ok(err) = io_uring_disabled_rx.recv().await {
641 if let Some(err) = err {
642 global_logger
643 .send(LogMessage::new(
644 format!("Can't configure io_uring: {err}. Ferron may run with io_uring disabled."),
645 true,
646 ))
647 .await
648 .unwrap_or_default();
649 break;
650 }
651 }
652
653 io_uring_disabled_rx.close();
654 });
655 } else {
656 io_uring_disabled_rx.close();
657 }
658
659 let mut acme_configs = tls_build_ctx.acme_configs;
660 let mut acme_on_demand_configs = tls_build_ctx.acme_on_demand_configs;
661 let memory_acme_account_cache_data_clone = memory_acme_account_cache_data.clone();
662
663 let (acme_configs, acme_on_demand_configs, existing_combinations) = secondary_runtime_ref.block_on(async move {
665 let mut existing_combinations = HashSet::new();
666
667 for acme_config in &mut acme_configs {
668 check_certificate_validity_or_install_cached(acme_config, None)
670 .await
671 .unwrap_or_default();
672 }
673
674 for acme_on_demand_config in &mut acme_on_demand_configs {
675 for cached_domain in get_cached_domains(acme_on_demand_config).await {
676 let mut acme_config = convert_on_demand_config(
677 acme_on_demand_config,
678 cached_domain.clone(),
679 memory_acme_account_cache_data_clone.clone(),
680 )
681 .await;
682
683 existing_combinations.insert((cached_domain, acme_on_demand_config.port));
684
685 check_certificate_validity_or_install_cached(&mut acme_config, None)
687 .await
688 .unwrap_or_default();
689
690 acme_configs.push(acme_config);
691 }
692 }
693
694 (acme_configs, acme_on_demand_configs, existing_combinations)
695 });
696
697 let inner_handler_data = ReloadableHandlerData {
698 configurations: server_configurations,
699 tls_configs: Arc::new(tls_configs),
700 http3_enabled: !quic_listened_socket_addresses.is_empty(),
701 acme_tls_alpn_01_configs: Arc::new(acme_tls_alpn_01_configs),
702 acme_http_01_resolvers: tls_build_ctx.acme_http_01_resolvers,
703 enable_proxy_protocol,
704 };
705 let reloadable_handler_data = if let Some(data) = SERVER_CONFIG_ARCSWAP.get().cloned() {
706 data.swap(Arc::new(inner_handler_data));
707 data
708 } else {
709 let reloadable_handler_data = Arc::new(ArcSwap::from_pointee(inner_handler_data));
710 let _ = SERVER_CONFIG_ARCSWAP.set(reloadable_handler_data.clone());
711 reloadable_handler_data
712 };
713
714 let mut start_new_handlers = true;
715 if let Ok(mut handlers_locked) = HANDLERS.lock() {
716 if shutdown_handlers {
717 while let Some((cancel_token, _)) = handlers_locked.pop() {
718 cancel_token.cancel();
719 }
720 } else {
721 for (_, graceful_shutdown) in handlers_locked.iter() {
722 start_new_handlers = false;
723 let _ = graceful_shutdown.send_blocking(());
724 }
725 }
726 }
727
728 let acme_on_demand_rx = tls_build_ctx.acme_on_demand_rx;
729 let on_demand_tls_ask_endpoint = match global_configuration
730 .as_ref()
731 .and_then(|c| get_value!("auto_tls_on_demand_ask", c))
732 .and_then(|v| v.as_str())
733 .map(|u| u.parse::<hyper::Uri>())
734 {
735 Some(Ok(uri)) => Some(uri),
736 Some(Err(err)) => Err(anyhow::anyhow!(
737 "Failed to parse automatic TLS on demand asking endpoint URI: {}",
738 err
739 ))?,
740 None => None,
741 };
742 let on_demand_tls_ask_endpoint_verify = !global_configuration
743 .as_ref()
744 .and_then(|c| get_value!("auto_tls_on_demand_ask_no_verification", c))
745 .and_then(|v| v.as_bool())
746 .unwrap_or(false);
747
748 background_cancel_token_ref.cancel();
750 *background_cancel_token_ref = CancellationToken::new();
751
752 if !acme_configs.is_empty() || !acme_on_demand_configs.is_empty() {
753 let acme_logger = ErrorLogger::new_multiple(
755 global_configuration
756 .as_ref()
757 .map_or(vec![], |c| c.observability.log_channels.clone()),
758 );
759 secondary_runtime_ref.spawn(background_acme_task(
760 acme_configs,
761 acme_on_demand_configs,
762 memory_acme_account_cache_data,
763 acme_on_demand_rx,
764 on_demand_tls_ask_endpoint,
765 on_demand_tls_ask_endpoint_verify,
766 acme_logger,
767 crypto_provider,
768 existing_combinations,
769 Some(background_cancel_token_ref.clone()),
770 ));
771 }
772
773 #[cfg(any(target_os = "linux", target_os = "android"))]
775 if let Some(metrics_channels) = global_configuration
776 .as_ref()
777 .map(|c| &c.observability.metric_channels)
778 .cloned()
779 {
780 let background_cancel_token = background_cancel_token_ref.clone();
781 secondary_runtime_ref.spawn(async move {
782 tokio::select! {
783 biased;
784
785 _ = background_cancel_token.cancelled() => {}
786 _ = crate::setup::metrics::background_metrics(
787 metrics_channels,
788 available_parallelism,
789 ) => {}
790 }
791 });
792 }
793
794 if start_new_handlers {
796 let mut handler_shutdown_channels = HANDLERS.lock().expect("Can't access the handler threads");
797
798 let multi_cancel = Arc::new(MultiCancel::new(available_parallelism.saturating_sub(1)));
801
802 for _ in 0..available_parallelism {
803 handler_shutdown_channels.push(create_http_handler(
804 reloadable_handler_data.clone(),
805 listener_handler_rx.clone(),
806 enable_uring,
807 io_uring_disabled_tx.clone(),
808 multi_cancel.clone(),
809 )?);
810 }
811 }
812
813 if listened_socket_addresses.is_empty() && quic_listened_socket_addresses.is_empty() {
815 Err(anyhow::anyhow!("The server is configured to listen to no port"))?
816 }
817
818 let tcp_send_buffer_size = global_configuration
819 .as_deref()
820 .and_then(|c| get_value!("tcp_send_buffer", c))
821 .and_then(|v| v.as_i128())
822 .map(|v| v as usize);
823 let tcp_recv_buffer_size = global_configuration
824 .as_deref()
825 .and_then(|c| get_value!("tcp_recv_buffer", c))
826 .and_then(|v| v.as_i128())
827 .map(|v| v as usize);
828 for (socket_address, encrypted) in listened_socket_addresses {
829 if let std::collections::hash_map::Entry::Vacant(e) = tcp_listeners.entry(socket_address) {
830 e.insert(create_tcp_listener(
832 socket_address,
833 encrypted,
834 listener_handler_tx.clone(),
835 enable_uring,
836 global_logger.clone(),
837 first_startup,
838 (tcp_send_buffer_size, tcp_recv_buffer_size),
839 io_uring_disabled_tx.clone(),
840 )?);
841 }
842 }
843
844 drop(tcp_listeners);
846
847 for (socket_address, tls_config) in quic_listened_socket_addresses {
848 if let Some(quic_listener_entry) = quic_listeners.get(&socket_address) {
849 let (_, tls_quic_listener) = quic_listener_entry;
851 tls_quic_listener.send_blocking(tls_config).unwrap_or_default();
852 } else {
853 quic_listeners.insert(
855 socket_address,
856 create_quic_listener(
857 socket_address,
858 tls_config,
859 listener_handler_tx.clone(),
860 global_logger.clone(),
861 first_startup,
862 )?,
863 );
864 }
865 }
866
867 drop(quic_listeners);
869
870 let shutdown_result = handle_shutdown_signals(secondary_runtime_ref);
871
872 Ok::<_, Box<dyn Error + Send + Sync>>(shutdown_result)
873 };
874
875 match execute_rest() {
876 Ok(to_restart) => {
877 if to_restart {
878 first_startup = false;
879 println!("Reloading the server configuration...");
880 } else {
881 if let Ok(mut handlers_locked) = HANDLERS.lock() {
882 while let Some((cancel_token, _)) = handlers_locked.pop() {
883 cancel_token.cancel();
884 }
885 }
886 drop(secondary_runtime);
887 break;
888 }
889 }
890 Err(err) => {
891 for logging_tx in global_configuration_clone
892 .as_ref()
893 .map_or(&vec![], |c| &c.observability.log_channels)
894 {
895 logging_tx
896 .send_blocking(LogMessage::new(err.to_string(), true))
897 .unwrap_or_default();
898 }
899 std::thread::sleep(Duration::from_millis(100));
900 Err(err)?
901 }
902 }
903
904 drop(observability_backend_loaders);
905 drop(module_loaders);
906 }
907
908 Ok(())
909}
910
911fn obtain_configuration_adapters() -> (
912 HashMap<String, Box<dyn ConfigurationAdapter + Send + Sync>>,
913 Vec<&'static str>,
914) {
915 let mut configuration_adapters: HashMap<String, Box<dyn ConfigurationAdapter + Send + Sync>> = HashMap::new();
917 let mut all_adapters = Vec::new();
918
919 macro_rules! register_configuration_adapter {
921 ($name:literal, $adapter:expr) => {
922 configuration_adapters.insert($name.to_string(), Box::new($adapter));
923 all_adapters.push($name);
924 };
925 }
926
927 register_configuration_adapter!("kdl", config::adapters::kdl::KdlConfigurationAdapter::new());
929 #[cfg(feature = "config-yaml-legacy")]
930 register_configuration_adapter!(
931 "yaml-legacy",
932 config::adapters::yaml_legacy::YamlLegacyConfigurationAdapter::new()
933 );
934 #[cfg(feature = "config-docker-auto")]
935 register_configuration_adapter!(
936 "docker-auto",
937 config::adapters::docker_auto::DockerAutoConfigurationAdapter::new()
938 );
939
940 (configuration_adapters, all_adapters)
941}
942
943#[cfg(feature = "config-yaml-legacy")]
945fn determine_default_configuration_adapter(path: &Path) -> &'static str {
946 match path
947 .extension()
948 .and_then(|s| s.to_str())
949 .map(|s| s.to_lowercase())
950 .as_deref()
951 {
952 Some("yaml") | Some("yml") => "yaml-legacy",
953 _ => "kdl",
954 }
955}
956
957#[cfg(not(feature = "config-yaml-legacy"))]
959fn determine_default_configuration_adapter(_path: &Path) -> &'static str {
960 "kdl"
961}
962
963fn print_version() {
964 println!("Ferron {}", build::PKG_VERSION);
966 println!(" Compiled on: {}", build::BUILD_TIME);
967 println!(" Git commit: {}", build::COMMIT_HASH);
968 println!(" Build target: {}", build::BUILD_TARGET);
969 println!(" Rust version: {}", build::RUST_VERSION);
970 println!(" Build host: {}", build::BUILD_OS);
971 if shadow_rs::is_debug() {
972 println!("WARNING: This is a debug build. It is not recommended for production use.");
973 }
974}
975
976fn main() {
978 setup_panic!(Metadata::new("Ferron", env!("CARGO_PKG_VERSION"))
980 .homepage("https://ferron.sh")
981 .support("- Send an email message to hello@ferron.sh"));
982
983 let (configuration_adapters, _all_adapters) = obtain_configuration_adapters();
985
986 let args = FerronArgs::parse();
988
989 if args.module_config {
990 println!("{}", ferron_load_modules::FERRON_BUILD_YAML);
992 return;
993 } else if args.version {
994 print_version();
995 return;
996 }
997
998 if let Err(err) = before_starting_server(args, configuration_adapters) {
1000 eprintln!("Error while running a server: {err}");
1001 std::process::exit(1);
1002 }
1003}