This commit is contained in:
Mateusz Gruszczyński committed 2026-10-05 19:05:55 +02:00
1 parent ddc5c6593f
commit b9d137eee1
63 files changed
+1232 -445

No files matched your search

+6
View File
@@ -238,6 +238,12 @@ pub struct CompiledFrontend {
pub pages: crate::pages::VhostPages,
pub proxy_timeouts: crate::vhost::ProxyTimeouts,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ResolvedLogVhost {
pub vhost: String,
pub matched_by: &'static str,
}
pub struct Snapshot {
pub vhost_metrics: std::collections::BTreeMap<String, Arc<crate::metrics::VhostMetrics>>,
pub forwarding: crate::forwarding::Compiled,
+48
View File
@@ -93,6 +93,54 @@ impl Snapshot {
}
None
}
/// Resolve a persistent protocol-error record to a configured vhost using
/// the same exact/wildcard precedence and listener binding rules as normal routing.
/// Client-provided Host/SNI values are never used as file names directly.
pub fn resolve_logging_vhost(
&self,
local: SocketAddr,
tls: bool,
routed_vhost: Option<&str>,
authority: Option<&str>,
host: Option<&str>,
sni: Option<&str>,
) -> Option<ResolvedLogVhost> {
if let Some(routed) = routed_vhost.filter(|value| !value.is_empty()) {
if self.frontends.values().flatten().any(|frontend| {
frontend.id == routed
&& frontend
.bindings
.iter()
.any(|binding| binding.matches(local, tls))
}) {
return Some(ResolvedLogVhost {
vhost: routed.to_owned(),
matched_by: "router",
});
}
}
for (candidate, matched_by) in [
(authority, "authority"),
(host, "host"),
(sni, "sni"),
] {
let Some(candidate) = candidate else {
continue;
};
let Ok(normalized) = request_host(candidate) else {
continue;
};
if let Some(frontend) = self.frontend(&normalized, local, tls) {
return Some(ResolvedLogVhost {
vhost: frontend.id.clone(),
matched_by,
});
}
}
None
}
/// Select a redirect host/rule using the accepted socket, TLS state and normalized path.
/// Exact hostnames win over the longest matching wildcard, matching vhost behavior.
pub fn redirect_on(
+51
View File
@@ -187,6 +187,57 @@ fn wildcard_host_patterns_are_normalized_and_exact_hosts_win() {
"wildcard/main"
);
}
#[test]
fn logging_vhost_resolution_reuses_router_host_precedence() {
let mut config = demo_config("127.0.0.1:9000".parse().unwrap());
config.vhosts[0].id = "wildcard".into();
config.vhosts[0].frontend.hosts = vec!["*.example.test".into()];
let mut exact = config.vhosts[0].clone();
exact.id = "exact".into();
exact.frontend.hosts = vec!["api.example.test".into()];
config.vhosts.push(exact);
let snapshot = compile(config, 1, &policy()).unwrap();
let local: SocketAddr = "127.0.0.1:8080".parse().unwrap();
let routed = snapshot
.resolve_logging_vhost(
local,
false,
Some("wildcard"),
Some("api.example.test"),
None,
None,
)
.unwrap();
assert_eq!(routed.vhost, "wildcard");
assert_eq!(routed.matched_by, "router");
let exact = snapshot
.resolve_logging_vhost(local, false, None, Some("API.EXAMPLE.TEST:8080"), None, None)
.unwrap();
assert_eq!(exact.vhost, "exact");
assert_eq!(exact.matched_by, "authority");
let wildcard = snapshot
.resolve_logging_vhost(local, false, None, None, Some("www.example.test:8080"), None)
.unwrap();
assert_eq!(wildcard.vhost, "wildcard");
assert_eq!(wildcard.matched_by, "host");
let sni = snapshot
.resolve_logging_vhost(local, false, None, None, None, Some("api.example.test"))
.unwrap();
assert_eq!(sni.vhost, "exact");
assert_eq!(sni.matched_by, "sni");
assert!(snapshot
.resolve_logging_vhost(local, false, None, None, None, Some("unknown.test"))
.is_none());
assert!(snapshot
.resolve_logging_vhost(local, false, None, None, None, None)
.is_none());
}
#[test]
fn reusable_acl_profile_reference_is_compiled_and_unknown_reference_fails() {
let mut c = demo_config("127.0.0.1:9000".parse().unwrap());