Skip to content

Commit 9f2e8fa

Browse files
committed
Extract access policy config
1 parent 2ae90ba commit 9f2e8fa

3 files changed

Lines changed: 277 additions & 267 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ behavior when the change improves security or project direction.
7474
and curve policy, and static certificate path validation into `config_tls`.
7575
- Move header policy config structs, overlay merge logic, HSTS defaults, and
7676
response rewrite policy types into `config_header`.
77+
- Move access policy, rate limit, and concurrency limit config into
78+
`config_access`.
7779

7880
## 1.4.2 - 2026-05-27
7981

src/config.rs

Lines changed: 3 additions & 267 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ use std::fs;
55
use std::net::IpAddr;
66
use std::path::{Path, PathBuf};
77

8-
use crate::config_access::{validate_access_rule_list, validate_client_cert_sha256_list};
8+
pub use crate::config_access::{
9+
AccessPolicyConfig, ConcurrencyLimitConfig, RateLimitConfig, RateLimitMode,
10+
};
911
#[cfg(test)]
1012
pub(crate) use crate::config_acme::MAX_ACME_ISSUERS;
1113
pub use crate::config_acme::{
@@ -1887,272 +1889,6 @@ impl VhostConfig {
18871889
}
18881890
}
18891891

1890-
#[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize)]
1891-
#[serde(deny_unknown_fields)]
1892-
pub struct AccessPolicyConfig {
1893-
#[serde(default = "default_true")]
1894-
pub enabled: bool,
1895-
#[serde(default)]
1896-
pub allow: Vec<String>,
1897-
#[serde(default)]
1898-
pub deny: Vec<String>,
1899-
#[serde(default)]
1900-
pub require_client_cert: bool,
1901-
#[serde(default)]
1902-
pub allow_client_cert_sha256: Vec<String>,
1903-
#[serde(default)]
1904-
pub deny_client_cert_sha256: Vec<String>,
1905-
}
1906-
1907-
impl Default for AccessPolicyConfig {
1908-
fn default() -> Self {
1909-
Self {
1910-
enabled: true,
1911-
allow: Vec::new(),
1912-
deny: Vec::new(),
1913-
require_client_cert: false,
1914-
allow_client_cert_sha256: Vec::new(),
1915-
deny_client_cert_sha256: Vec::new(),
1916-
}
1917-
}
1918-
}
1919-
1920-
impl AccessPolicyConfig {
1921-
fn validate(&self, scope: &'static str) -> Result<(), ConfigError> {
1922-
validate_access_rule_list(scope, "allow", &self.allow)?;
1923-
validate_access_rule_list(scope, "deny", &self.deny)?;
1924-
validate_client_cert_sha256_list(
1925-
scope,
1926-
"allow_client_cert_sha256",
1927-
&self.allow_client_cert_sha256,
1928-
)?;
1929-
validate_client_cert_sha256_list(
1930-
scope,
1931-
"deny_client_cert_sha256",
1932-
&self.deny_client_cert_sha256,
1933-
)?;
1934-
Ok(())
1935-
}
1936-
}
1937-
1938-
const MAX_RATE_LIMIT_REQUESTS_PER_SECOND: u32 = 1_000_000;
1939-
const MAX_RATE_LIMIT_BURST: u32 = 1_000_000;
1940-
const MAX_RATE_LIMIT_TABLE_ENTRIES: usize = 1_000_000;
1941-
const MAX_RATE_LIMIT_ENTRY_TTL_SECS: u64 = 86_400;
1942-
const MAX_RATE_LIMIT_DELAY_MS: u64 = 60_000;
1943-
1944-
#[derive(Debug, Clone, Copy, Default, Eq, PartialEq, Deserialize, Serialize)]
1945-
#[serde(rename_all = "kebab-case")]
1946-
pub enum RateLimitMode {
1947-
#[default]
1948-
Nodelay,
1949-
Delay,
1950-
}
1951-
1952-
#[derive(Debug, Clone, Copy, Eq, PartialEq, Deserialize, Serialize)]
1953-
#[serde(deny_unknown_fields)]
1954-
pub struct RateLimitConfig {
1955-
#[serde(default)]
1956-
pub enabled: bool,
1957-
#[serde(default)]
1958-
pub requests_per_second: u32,
1959-
#[serde(default)]
1960-
pub burst: u32,
1961-
#[serde(default = "default_rate_limit_status")]
1962-
pub status: u16,
1963-
#[serde(default = "default_rate_limit_table_max_entries")]
1964-
pub table_max_entries: usize,
1965-
#[serde(default = "default_rate_limit_entry_ttl_secs")]
1966-
pub entry_ttl_secs: u64,
1967-
#[serde(default)]
1968-
pub mode: RateLimitMode,
1969-
#[serde(default = "default_rate_limit_max_delay_ms")]
1970-
pub max_delay_ms: u64,
1971-
#[serde(default)]
1972-
pub reject_indeterminate: bool,
1973-
}
1974-
1975-
impl Default for RateLimitConfig {
1976-
fn default() -> Self {
1977-
Self {
1978-
enabled: false,
1979-
requests_per_second: 0,
1980-
burst: 0,
1981-
status: default_rate_limit_status(),
1982-
table_max_entries: default_rate_limit_table_max_entries(),
1983-
entry_ttl_secs: default_rate_limit_entry_ttl_secs(),
1984-
mode: RateLimitMode::Nodelay,
1985-
max_delay_ms: default_rate_limit_max_delay_ms(),
1986-
reject_indeterminate: false,
1987-
}
1988-
}
1989-
}
1990-
1991-
impl RateLimitConfig {
1992-
fn validate(&self, scope: &'static str) -> Result<(), ConfigError> {
1993-
if !self.enabled {
1994-
return Ok(());
1995-
}
1996-
if self.requests_per_second == 0
1997-
|| self.requests_per_second > MAX_RATE_LIMIT_REQUESTS_PER_SECOND
1998-
{
1999-
return Err(ConfigError::InvalidRateLimit {
2000-
field: rate_limit_field(scope, "requests_per_second"),
2001-
});
2002-
}
2003-
if self.burst > MAX_RATE_LIMIT_BURST {
2004-
return Err(ConfigError::InvalidRateLimit {
2005-
field: rate_limit_field(scope, "burst"),
2006-
});
2007-
}
2008-
if !(400..=599).contains(&self.status) {
2009-
return Err(ConfigError::InvalidRateLimit {
2010-
field: rate_limit_field(scope, "status"),
2011-
});
2012-
}
2013-
if self.table_max_entries == 0 || self.table_max_entries > MAX_RATE_LIMIT_TABLE_ENTRIES {
2014-
return Err(ConfigError::InvalidRateLimit {
2015-
field: rate_limit_field(scope, "table_max_entries"),
2016-
});
2017-
}
2018-
if self.entry_ttl_secs == 0 || self.entry_ttl_secs > MAX_RATE_LIMIT_ENTRY_TTL_SECS {
2019-
return Err(ConfigError::InvalidRateLimit {
2020-
field: rate_limit_field(scope, "entry_ttl_secs"),
2021-
});
2022-
}
2023-
if matches!(self.mode, RateLimitMode::Delay) && self.max_delay_ms == 0 {
2024-
return Err(ConfigError::InvalidRateLimit {
2025-
field: rate_limit_field(scope, "max_delay_ms"),
2026-
});
2027-
}
2028-
if self.max_delay_ms > MAX_RATE_LIMIT_DELAY_MS {
2029-
return Err(ConfigError::InvalidRateLimit {
2030-
field: rate_limit_field(scope, "max_delay_ms"),
2031-
});
2032-
}
2033-
2034-
Ok(())
2035-
}
2036-
}
2037-
2038-
fn default_rate_limit_status() -> u16 {
2039-
429
2040-
}
2041-
2042-
fn default_rate_limit_table_max_entries() -> usize {
2043-
65_536
2044-
}
2045-
2046-
fn default_rate_limit_entry_ttl_secs() -> u64 {
2047-
300
2048-
}
2049-
2050-
fn default_rate_limit_max_delay_ms() -> u64 {
2051-
1000
2052-
}
2053-
2054-
fn rate_limit_field(scope: &'static str, field: &'static str) -> &'static str {
2055-
match (scope, field) {
2056-
("vhosts.rate_limit", "requests_per_second") => "vhosts.rate_limit.requests_per_second",
2057-
("vhosts.rate_limit", "burst") => "vhosts.rate_limit.burst",
2058-
("vhosts.rate_limit", "status") => "vhosts.rate_limit.status",
2059-
("vhosts.rate_limit", "table_max_entries") => "vhosts.rate_limit.table_max_entries",
2060-
("vhosts.rate_limit", "entry_ttl_secs") => "vhosts.rate_limit.entry_ttl_secs",
2061-
("vhosts.rate_limit", "max_delay_ms") => "vhosts.rate_limit.max_delay_ms",
2062-
("vhosts.routes.rate_limit", "requests_per_second") => {
2063-
"vhosts.routes.rate_limit.requests_per_second"
2064-
}
2065-
("vhosts.routes.rate_limit", "burst") => "vhosts.routes.rate_limit.burst",
2066-
("vhosts.routes.rate_limit", "status") => "vhosts.routes.rate_limit.status",
2067-
("vhosts.routes.rate_limit", "table_max_entries") => {
2068-
"vhosts.routes.rate_limit.table_max_entries"
2069-
}
2070-
("vhosts.routes.rate_limit", "entry_ttl_secs") => "vhosts.routes.rate_limit.entry_ttl_secs",
2071-
("vhosts.routes.rate_limit", "max_delay_ms") => "vhosts.routes.rate_limit.max_delay_ms",
2072-
_ => "rate_limit",
2073-
}
2074-
}
2075-
2076-
const MAX_CONCURRENCY_LIMIT: usize = 1_000_000;
2077-
const MAX_CONCURRENCY_QUEUE_TIMEOUT_MS: u64 = 60_000;
2078-
2079-
#[derive(Debug, Clone, Copy, Eq, PartialEq, Deserialize, Serialize)]
2080-
#[serde(deny_unknown_fields)]
2081-
pub struct ConcurrencyLimitConfig {
2082-
#[serde(default)]
2083-
pub enabled: bool,
2084-
#[serde(default)]
2085-
pub max_in_flight: usize,
2086-
#[serde(default)]
2087-
pub max_queue: usize,
2088-
#[serde(default = "default_concurrency_limit_status")]
2089-
pub status: u16,
2090-
#[serde(default)]
2091-
pub queue_timeout_ms: u64,
2092-
}
2093-
2094-
impl Default for ConcurrencyLimitConfig {
2095-
fn default() -> Self {
2096-
Self {
2097-
enabled: false,
2098-
max_in_flight: 0,
2099-
max_queue: 0,
2100-
status: default_concurrency_limit_status(),
2101-
queue_timeout_ms: 0,
2102-
}
2103-
}
2104-
}
2105-
2106-
impl ConcurrencyLimitConfig {
2107-
fn validate(&self, scope: &'static str) -> Result<(), ConfigError> {
2108-
if !self.enabled {
2109-
return Ok(());
2110-
}
2111-
if self.max_in_flight == 0 || self.max_in_flight > MAX_CONCURRENCY_LIMIT {
2112-
return Err(ConfigError::InvalidConcurrencyLimit {
2113-
field: concurrency_limit_field(scope, "max_in_flight"),
2114-
});
2115-
}
2116-
if self.max_queue > MAX_CONCURRENCY_LIMIT {
2117-
return Err(ConfigError::InvalidConcurrencyLimit {
2118-
field: concurrency_limit_field(scope, "max_queue"),
2119-
});
2120-
}
2121-
if !(400..=599).contains(&self.status) {
2122-
return Err(ConfigError::InvalidConcurrencyLimit {
2123-
field: concurrency_limit_field(scope, "status"),
2124-
});
2125-
}
2126-
if self.queue_timeout_ms > MAX_CONCURRENCY_QUEUE_TIMEOUT_MS {
2127-
return Err(ConfigError::InvalidConcurrencyLimit {
2128-
field: concurrency_limit_field(scope, "queue_timeout_ms"),
2129-
});
2130-
}
2131-
2132-
Ok(())
2133-
}
2134-
}
2135-
2136-
fn default_concurrency_limit_status() -> u16 {
2137-
503
2138-
}
2139-
2140-
fn concurrency_limit_field(scope: &'static str, field: &'static str) -> &'static str {
2141-
match (scope, field) {
2142-
("vhosts.concurrency", "max_in_flight") => "vhosts.concurrency.max_in_flight",
2143-
("vhosts.concurrency", "max_queue") => "vhosts.concurrency.max_queue",
2144-
("vhosts.concurrency", "status") => "vhosts.concurrency.status",
2145-
("vhosts.concurrency", "queue_timeout_ms") => "vhosts.concurrency.queue_timeout_ms",
2146-
("vhosts.routes.concurrency", "max_in_flight") => "vhosts.routes.concurrency.max_in_flight",
2147-
("vhosts.routes.concurrency", "max_queue") => "vhosts.routes.concurrency.max_queue",
2148-
("vhosts.routes.concurrency", "status") => "vhosts.routes.concurrency.status",
2149-
("vhosts.routes.concurrency", "queue_timeout_ms") => {
2150-
"vhosts.routes.concurrency.queue_timeout_ms"
2151-
}
2152-
_ => "concurrency",
2153-
}
2154-
}
2155-
21561892
#[derive(Debug, Clone, Copy, Eq, PartialEq, Deserialize, Serialize)]
21571893
#[serde(deny_unknown_fields)]
21581894
pub struct GrpcRouteConfig {

0 commit comments

Comments
 (0)