ferron/
main.rs

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// Set the global allocator to use mimalloc for performance optimization
55#[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
77/// Handles shutdown signals (SIGHUP and CTRL+C) and returns whether to continue running
78fn 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
109/// Function called before starting a server
110fn before_starting_server(
111  args: FerronArgs,
112  configuration_adapters: HashMap<String, Box<dyn ConfigurationAdapter + Send + Sync>>,
113) -> Result<(), Box<dyn Error + Send + Sync>> {
114  // When a config string is specified, a tempfile is written with the contents of the string and then
115  // the tempfile is used as the configuration path.
116  let temp_config_file: NamedTempFile;
117  // Obtain the argument values
118  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    // When a config string is specified but no configuration adapter is specified, default to using kdl.
214    "kdl"
215  } else {
216    determine_default_configuration_adapter(configuration_path)
217  };
218
219  // Obtain the configuration adapter
220  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  // Determine the available parallelism
228  let available_parallelism = thread::available_parallelism()?.get();
229
230  // First startup flag
231  let mut first_startup = true;
232
233  // Cancel token for ACME and process metrics
234  let mut background_cancel_token: CancellationToken = CancellationToken::new();
235
236  // Cancel token for OCSP stapling
237  let mut ocsp_cancel_token: CancellationToken = CancellationToken::new();
238
239  // Secondary Tokio runtime
240  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    // Obtain the module loaders
251    let mut module_loaders = obtain_module_loaders();
252
253    // Obtain the observability backend loaders
254    let mut observability_backend_loaders = obtain_observability_backend_loaders();
255
256    // Load the configuration
257    let configs_to_process = configuration_adapter.load_configuration(configuration_path)?;
258
259    // Process the configurations
260    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    // Finalize the configurations
271    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    // Reference to cancel tokens
279    let background_cancel_token_ref = &mut background_cancel_token;
280    let ocsp_cancel_token_ref = &mut ocsp_cancel_token;
281
282    // Execute the rest
283    let execute_rest = move || {
284      if let Some(first_module_error) = first_module_error {
285        // Error out if there was a module error
286        Err(first_module_error)?;
287      }
288
289      // Log unused properties
290      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      // Configure cryptography provider for Rustls
305      let crypto_provider = init_crypto_provider(global_configuration.as_deref())?;
306
307      // Install a process-wide cryptography provider. If it fails, then error it out.
308      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      // Build TLS configuration
315      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      // Iterate server configurations (TLS configuration)
386      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 HTTP/1.1 isn't enabled, don't listen to non-encrypted ports
459      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      // Cancel OCSP stapling background tasks
470      ocsp_cancel_token_ref.cancel();
471      *ocsp_cancel_token_ref = CancellationToken::new();
472
473      // Create TLS server configurations
474      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          // The `ocsp_stapler` crate is dependent on Tokio, so we create a stapler in the Tokio runtime...
486          // If this wasn't wrapped in a Tokio runtime, creation of a OCSP stapler would just cause a panic.
487          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          // TLS configuration used for QUIC listener
512          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          // Shut down the TCP listener
579          value.cancel();
580
581          // Push the the TCP listener address to remove
582          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          // Shut down the QUIC listener
595          value.0.cancel();
596
597          // Push the the QUIC listener address to remove
598          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        // Remove the TCP listener
606        tcp_listeners.remove(&key_to_remove);
607      }
608
609      for key_to_remove in quic_listener_socketaddrs_to_remove {
610        // Remove the QUIC listener
611        quic_listeners.remove(&key_to_remove);
612      }
613
614      // Get a global logger for listeners
615      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      // Preload the cached certificates before spawning the background ACME task
664      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          // Install the certificates from the cache if they're valid
669          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            // Install the certificates from the cache if they're valid
686            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      // Cancel some background tasks
749      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        // Spawn a task to handle ACME certificate provisioning, one certificate at time
754        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      // Process metrics initialization
774      #[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      // Spawn request handler threads
795      if start_new_handlers {
796        let mut handler_shutdown_channels = HANDLERS.lock().expect("Can't access the handler threads");
797
798        // The number of handler threads, minus one for the multi-cancel, because without "minus one",
799        // there would be a "deadlock" when shutting down handler threads, and they won't be able to shut down
800        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      // Error out, if server is configured to listen to no port
814      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          // Create a TCP listener
831          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 listener mutex guard
845      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          // Replace the TLS configuration in the QUIC listener
850          let (_, tls_quic_listener) = quic_listener_entry;
851          tls_quic_listener.send_blocking(tls_config).unwrap_or_default();
852        } else {
853          // Create a QUIC listener
854          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 listener mutex guard
868      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  // Configuration adapters
916  let mut configuration_adapters: HashMap<String, Box<dyn ConfigurationAdapter + Send + Sync>> = HashMap::new();
917  let mut all_adapters = Vec::new();
918
919  // Configuration adapter registration macro
920  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 adapters
928  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/// Determines the default configuration adapter
944#[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/// Determines the default configuration adapter
958#[cfg(not(feature = "config-yaml-legacy"))]
959fn determine_default_configuration_adapter(_path: &Path) -> &'static str {
960  "kdl"
961}
962
963fn print_version() {
964  // Print the server version and build information
965  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
976/// The main entry point of the application
977fn main() {
978  // Set the panic handler
979  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  // Obtain the configuration adapters
984  let (configuration_adapters, _all_adapters) = obtain_configuration_adapters();
985
986  // Parse command-line arguments
987  let args = FerronArgs::parse();
988
989  if args.module_config {
990    // Dump the used compile-time module configuration and exit
991    println!("{}", ferron_load_modules::FERRON_BUILD_YAML);
992    return;
993  } else if args.version {
994    print_version();
995    return;
996  }
997
998  // Start the server!
999  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}