Skip to main content

o_sfu/config/
http.rs

1use std::{net::SocketAddr, time::Duration};
2
3use anyhow::{Context, Result, ensure};
4use ipnet::IpNet;
5use tokio::sync::Semaphore;
6
7use super::{DeadlineDuration, HttpConfig, env::Env};
8
9impl HttpConfig {
10    /// Validates proxy policy and listener limits before runtime startup.
11    ///
12    /// # Errors
13    /// Returns [`anyhow::Error`] for proxy mode without trusted proxies, zero or
14    /// unsupported semaphore capacity or a header deadline outside one second
15    /// through one day.
16    pub(crate) fn validate(&self) -> Result<()> {
17        ensure!(
18            !self.trust_proxy_headers || !self.trusted_proxies.is_empty(),
19            "TRUSTED_PROXIES must contain at least one proxy CIDR when PROXY=true"
20        );
21        ensure!(
22            (1..=Semaphore::MAX_PERMITS).contains(&self.max_http_connections),
23            "MAX_HTTP_CONNECTIONS must be between 1 and {}",
24            Semaphore::MAX_PERMITS
25        );
26        ensure!(
27            (Duration::from_secs(1)..=Duration::from_hours(24)).contains(&self.header_read_timeout),
28            "HEADER_READ_TIMEOUT must be between 1 and 86400 seconds"
29        );
30        Ok(())
31    }
32
33    pub(super) fn from_env(env: &Env<'_>) -> Result<Self> {
34        let trust_proxy_headers = env.var("PROXY").default(false)?;
35        let trusted_proxies = env
36            .var::<String>("TRUSTED_PROXIES")
37            .optional()?
38            .map(|raw| {
39                raw.split(',')
40                    .map(|cidr| {
41                        cidr.trim()
42                            .parse::<IpNet>()
43                            .context("TRUSTED_PROXIES must be a comma-separated list of IP CIDRs")
44                    })
45                    .collect::<Result<Vec<_>>>()
46            })
47            .transpose()?
48            .unwrap_or_default();
49        let config = Self {
50            bind_address: env
51                .var("HTTP_INTERFACE")
52                .alias("BIND_ADDRESS")
53                .default(SocketAddr::from(([0, 0, 0, 0], 8070)))?,
54            trust_proxy_headers,
55            trusted_proxies,
56            max_http_connections: env.var("MAX_HTTP_CONNECTIONS").default(4096)?,
57            header_read_timeout: env
58                .var("HEADER_READ_TIMEOUT")
59                .default(Duration::from_secs(10))?,
60            shutdown_timeout: env
61                .var("SHUTDOWN_TIMEOUT_MS")
62                .default(DeadlineDuration::from_millis(10_000)?)?,
63        };
64        config.validate()?;
65        Ok(config)
66    }
67}