v0.34.4
This commit is contained in:
1 parent
ee174bc283
commit
52e7ce7b46
24 files changed
+672
-418
No files matched your search
+3
-10
@@ -58,10 +58,7 @@ pub struct MethodPolicy {
|
||||
}
|
||||
impl MethodPolicy {
|
||||
pub fn validate(&mut self) -> Result<()> {
|
||||
ensure!(
|
||||
self.methods.len() <= 32,
|
||||
"method policy allows at most 32 methods"
|
||||
);
|
||||
ensure!(self.methods.len() <= 32, "method policy allows at most 32 methods");
|
||||
let mut seen = std::collections::HashSet::new();
|
||||
for method in &mut self.methods {
|
||||
*method = method.trim().to_ascii_uppercase();
|
||||
@@ -69,10 +66,7 @@ impl MethodPolicy {
|
||||
!method.is_empty() && method.len() <= 32 && method.parse::<http::Method>().is_ok(),
|
||||
"invalid HTTP method in method policy"
|
||||
);
|
||||
ensure!(
|
||||
seen.insert(method.clone()),
|
||||
"duplicate HTTP method in method policy"
|
||||
);
|
||||
ensure!(seen.insert(method.clone()), "duplicate HTTP method in method policy");
|
||||
}
|
||||
ensure!(
|
||||
self.mode == MethodPolicyMode::Off || !self.methods.is_empty(),
|
||||
@@ -322,8 +316,7 @@ pub struct Vhost {
|
||||
pub headers: HeaderRules,
|
||||
#[serde(default)]
|
||||
pub security_headers: SecurityHeaders,
|
||||
#[serde(default)]
|
||||
pub user_agent_blocking: crate::user_agent::Policy,
|
||||
#[serde(default)] pub user_agent_blocking: crate::user_agent::Policy,
|
||||
/// Nginx-style upstream timeout controls. Empty values inherit process defaults.
|
||||
#[serde(default)]
|
||||
pub proxy_timeouts: ProxyTimeouts,
|
||||
|
||||
+13
-41
@@ -71,10 +71,7 @@ impl Vhost {
|
||||
!self.websocket_rfc9220 || self.http3_enabled,
|
||||
"RFC 9220 requires HTTP/3 to be enabled for the vhost"
|
||||
);
|
||||
ensure!(
|
||||
!self.frontend.hosts.is_empty(),
|
||||
"vhost requires at least one hostname"
|
||||
);
|
||||
ensure!(!self.frontend.hosts.is_empty(), "vhost requires at least one hostname");
|
||||
let mut hosts = std::collections::HashSet::new();
|
||||
for host in &mut self.frontend.hosts {
|
||||
*host = crate::config::normalize_host_pattern(host)?;
|
||||
@@ -164,10 +161,7 @@ impl Vhost {
|
||||
"location cannot define both a local response and a redirect"
|
||||
);
|
||||
if let Some(id) = &route.acl_profile_id {
|
||||
ensure!(
|
||||
crate::config::valid_id(id),
|
||||
"invalid location ACL profile id"
|
||||
);
|
||||
ensure!(crate::config::valid_id(id), "invalid location ACL profile id");
|
||||
}
|
||||
route.country_access.validate()?;
|
||||
route.method_policy.validate()?;
|
||||
@@ -205,21 +199,13 @@ impl Vhost {
|
||||
// Reject cycles at configuration time; a runtime depth guard remains as a
|
||||
// second line of defense for hot-reload/state inconsistencies.
|
||||
let mut starts = vec![None];
|
||||
starts.extend(
|
||||
self.routes
|
||||
.iter()
|
||||
.filter(|route| route.enabled)
|
||||
.map(|route| Some(route.id.as_str())),
|
||||
);
|
||||
starts.extend(self.routes.iter().filter(|route| route.enabled).map(|route| Some(route.id.as_str())));
|
||||
for start in starts {
|
||||
let mut seen = std::collections::HashSet::new();
|
||||
let mut current = start;
|
||||
loop {
|
||||
let key = current.unwrap_or("<main>");
|
||||
ensure!(
|
||||
seen.insert(key.to_owned()),
|
||||
"recursive error fallback loop detected"
|
||||
);
|
||||
ensure!(seen.insert(key.to_owned()), "recursive error fallback loop detected");
|
||||
let fallback = match current {
|
||||
None => self.error_fallback.as_ref(),
|
||||
Some(id) => self
|
||||
@@ -237,9 +223,7 @@ impl Vhost {
|
||||
if let Some(custom) = &member.health_check {
|
||||
let mut settings = self.load_balancing.clone();
|
||||
settings.health_check = custom.clone();
|
||||
settings
|
||||
.validate()
|
||||
.with_context(|| format!("backend {} health check", member.id))?;
|
||||
settings.validate().with_context(|| format!("backend {} health check", member.id))?;
|
||||
}
|
||||
}
|
||||
self.proxy_timeouts.validate()?;
|
||||
@@ -260,8 +244,7 @@ impl Vhost {
|
||||
"choose either Tinyauth or Basic authentication"
|
||||
);
|
||||
self.pages.validate()?;
|
||||
self.transform
|
||||
.resolve(&crate::transform::Settings::default())?;
|
||||
self.transform.resolve(&crate::transform::Settings::default())?;
|
||||
self.security_headers.compile()?;
|
||||
self.user_agent_blocking.compile()?;
|
||||
self.headers.compile()?;
|
||||
@@ -336,10 +319,8 @@ pub fn validate_listener(listener: Listener) -> Result<()> {
|
||||
/// counterpart must both be routable, even if only one was configured.
|
||||
fn www_partner(host: &str) -> Result<String> {
|
||||
if let Some(bare) = host.strip_prefix("www.") {
|
||||
ensure!(
|
||||
!bare.is_empty() && bare.parse::<std::net::IpAddr>().is_err(),
|
||||
"www redirect requires a DNS hostname"
|
||||
);
|
||||
ensure!(!bare.is_empty() && bare.parse::<std::net::IpAddr>().is_err(),
|
||||
"www redirect requires a DNS hostname");
|
||||
crate::config::normalize_host(bare)
|
||||
} else {
|
||||
crate::config::normalize_host(&format!("www.{host}"))
|
||||
@@ -347,23 +328,14 @@ fn www_partner(host: &str) -> Result<String> {
|
||||
}
|
||||
impl Vhost {
|
||||
fn www_canonical_host(&self) -> Result<&str> {
|
||||
let canonical = self
|
||||
.www_redirect_target
|
||||
.as_deref()
|
||||
let canonical = self.www_redirect_target.as_deref()
|
||||
.or_else(|| self.frontend.hosts.first().map(String::as_str))
|
||||
.ok_or_else(|| anyhow::anyhow!("vhost requires at least one hostname"))?;
|
||||
ensure!(
|
||||
!canonical.starts_with("*.") && canonical.parse::<std::net::IpAddr>().is_err(),
|
||||
"www redirect requires an exact DNS hostname"
|
||||
);
|
||||
ensure!(!canonical.starts_with("*.") && canonical.parse::<std::net::IpAddr>().is_err(),
|
||||
"www redirect requires an exact DNS hostname");
|
||||
let partner = www_partner(canonical)?;
|
||||
ensure!(
|
||||
self.frontend
|
||||
.hosts
|
||||
.iter()
|
||||
.any(|host| host == canonical || host == &partner),
|
||||
"www redirect target or its www/non-www partner must belong to this vhost"
|
||||
);
|
||||
ensure!(self.frontend.hosts.iter().any(|host| host == canonical || host == &partner),
|
||||
"www redirect target or its www/non-www partner must belong to this vhost");
|
||||
Ok(canonical)
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user