v0.29.2
This commit is contained in:
1 parent
76cb4acef0
commit
68678e98be
84 files changed
+1519
-325
No files matched your search
@@ -4,6 +4,7 @@ impl Default for PathRoute {
|
||||
source: Source::default(),
|
||||
backend_id: None,
|
||||
id: "root".into(),
|
||||
internal: false,
|
||||
path_prefix: root(),
|
||||
match_type: PathMatch::Prefix,
|
||||
enabled: true,
|
||||
@@ -16,6 +17,7 @@ impl Default for PathRoute {
|
||||
rewrite: PathRewrite::default(),
|
||||
response: None,
|
||||
redirect: None,
|
||||
error_fallback: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,6 +33,7 @@ impl PathRoute {
|
||||
&& self.enabled
|
||||
&& self.source == Source::ReverseProxy
|
||||
&& self.backend_id.is_none()
|
||||
&& !self.internal
|
||||
&& self.cache.is_none()
|
||||
&& self.acl_profile_id.is_none()
|
||||
&& self.acl.is_none()
|
||||
@@ -42,6 +45,7 @@ impl PathRoute {
|
||||
&& self.rewrite.value.is_empty()
|
||||
&& self.response.is_none()
|
||||
&& self.redirect.is_none()
|
||||
&& self.error_fallback.is_none()
|
||||
}
|
||||
}
|
||||
impl Vhost {
|
||||
@@ -140,7 +144,15 @@ impl Vhost {
|
||||
// Normalize the untouched pre-0.16 synthetic root route out of the custom
|
||||
// location list so adding/removing Custom locations cannot delete fallback.
|
||||
self.routes.retain(|route| !route.is_legacy_main_fallback());
|
||||
if let Some(fallback) = &mut self.error_fallback {
|
||||
fallback.validate()?;
|
||||
}
|
||||
let mut route_ids = std::collections::HashSet::new();
|
||||
for route in &mut self.routes {
|
||||
ensure!(
|
||||
crate::config::valid_id(&route.id) && route_ids.insert(route.id.clone()),
|
||||
"invalid/duplicate vhost path id"
|
||||
);
|
||||
route.source.validate()?;
|
||||
ensure!(
|
||||
route.response.is_none() || route.redirect.is_none(),
|
||||
@@ -155,11 +167,55 @@ impl Vhost {
|
||||
route.source.is_reverse_proxy() || route.backend_id.is_none(),
|
||||
"Web Server location cannot pin a reverse-proxy backend"
|
||||
);
|
||||
if let Some(fallback) = &mut route.error_fallback {
|
||||
fallback.validate()?;
|
||||
}
|
||||
}
|
||||
ensure!(
|
||||
self.routes.len() <= 64,
|
||||
"at most 64 custom locations per vhost"
|
||||
);
|
||||
let resolve_target = |target: &str| {
|
||||
self.routes
|
||||
.iter()
|
||||
.find(|route| route.id == target && route.enabled && route.internal)
|
||||
};
|
||||
if let Some(fallback) = &self.error_fallback {
|
||||
ensure!(
|
||||
resolve_target(&fallback.target).is_some(),
|
||||
"vhost error fallback target must reference an enabled internal location"
|
||||
);
|
||||
}
|
||||
for route in &self.routes {
|
||||
if let Some(fallback) = &route.error_fallback {
|
||||
ensure!(
|
||||
resolve_target(&fallback.target).is_some(),
|
||||
"location error fallback target must reference an enabled internal location"
|
||||
);
|
||||
}
|
||||
}
|
||||
// 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())));
|
||||
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");
|
||||
let fallback = match current {
|
||||
None => self.error_fallback.as_ref(),
|
||||
Some(id) => self
|
||||
.routes
|
||||
.iter()
|
||||
.find(|route| route.id == id)
|
||||
.and_then(|route| route.error_fallback.as_ref()),
|
||||
};
|
||||
let Some(fallback) = fallback else { break };
|
||||
current = Some(fallback.target.as_str());
|
||||
}
|
||||
}
|
||||
self.load_balancing.validate()?;
|
||||
self.proxy_timeouts.validate()?;
|
||||
self.rate_limit.validate()?;
|
||||
|
||||
Reference in new issue
Block a user