WEB: bounded opt-in wildcard host routing added

This commit is contained in:
Alexey
2026-10-17 23:42:26 +03:00
parent b2b088495d
commit 9738244285
67 changed files with 2572 additions and 239 deletions
+57 -5
View File
@@ -11,7 +11,7 @@ const WEB_OVERLOAD_CONNECTION_BYTES: usize = 4 * 1024;
const WEB_CAPABILITY_INDEX_ENTRY_BYTES: usize = 64;
/// Validates process-wide body, header, queue, static, and debug reservations.
pub(super) fn validate(limits: &WebLimitsConfig) -> Result<()> {
pub(super) fn validate(limits: &WebLimitsConfig, wildcard: bool) -> Result<()> {
if limits.max_carrier_learning_entries == 0 {
return config_error("web.limits.max_carrier_learning_entries must be > 0");
}
@@ -83,9 +83,15 @@ pub(super) fn validate(limits: &WebLimitsConfig) -> Result<()> {
.ok_or_else(|| {
ProxyError::Config("web.limits lane state reservation overflowed usize".to_string())
})?;
let wildcard_reservation = if wildcard {
wildcard_reservation(limits)?
} else {
0
};
let reserved = limits
.pending_bytes_global
.checked_add(limits.max_body_bytes_global)
.checked_add(wildcard_reservation)
.and_then(|value| value.checked_add(limits.max_body_bytes_global))
.and_then(|value| value.checked_add(limits.max_static_bytes))
.and_then(|value| value.checked_add(debug_ring_index))
.and_then(|value| value.checked_add(status_pages))
@@ -106,6 +112,52 @@ pub(super) fn validate(limits: &WebLimitsConfig) -> Result<()> {
Ok(())
}
// Cache entries include their digest index and allocator overhead. Detached entry
// leases remain charged until the last borrower releases them. Handler scratch and
// authenticated host bindings have independent existing concurrency ceilings.
fn wildcard_reservation(limits: &WebLimitsConfig) -> Result<usize> {
let wildcard = &limits.wildcard;
if wildcard.max_rules == 0
|| wildcard.max_profiles_per_request == 0
|| wildcard.cache_bytes == 0
|| wildcard.cold_hmac_per_minute == 0
|| (wildcard.cold_hmac_burst as usize) < wildcard.max_profiles_per_request
{
return config_error(
"web.limits.wildcard requires positive bounds and a burst covering a complete profile table",
);
}
let rules = wildcard
.max_rules
.checked_mul(1024)
.and_then(|value| {
limits
.max_profiles
.checked_mul(1024)
.and_then(|profiles| value.checked_add(profiles))
})
.ok_or_else(|| {
ProxyError::Config("WEB wildcard template reservations overflowed usize".to_string())
})?;
wildcard
.max_profiles_per_request
.checked_mul(32)
.and_then(|value| value.checked_add(1024))
.and_then(|value| value.checked_mul(limits.max_http_handlers))
.and_then(|value| value.checked_add(wildcard.cache_bytes))
.and_then(|value| value.checked_add(rules))
.and_then(|value| {
limits
.max_bootstraps_global
.checked_add(limits.max_sessions_global)
.and_then(|bindings| bindings.checked_mul(1024))
.and_then(|bindings| value.checked_add(bindings))
})
.ok_or_else(|| {
ProxyError::Config("WEB wildcard memory reservations overflowed usize".to_string())
})
}
#[cfg(test)]
mod tests {
use super::*;
@@ -113,13 +165,13 @@ mod tests {
#[test]
fn default_envelope_includes_bounded_lane_and_learning_metadata() {
let limits = WebLimitsConfig::default();
assert!(validate(&limits).is_ok());
assert!(validate(&limits, false).is_ok());
let previous_envelope = WebLimitsConfig {
memory_envelope_bytes: 768 * 1024 * 1024,
..limits
};
assert!(validate(&previous_envelope).is_err());
assert!(validate(&previous_envelope, false).is_err());
}
#[test]
@@ -128,7 +180,7 @@ mod tests {
max_profiles: usize::MAX,
..WebLimitsConfig::default()
};
let error = validate(&limits).unwrap_err().to_string();
let error = validate(&limits, false).unwrap_err().to_string();
assert!(error.contains("web capability index reservation overflowed usize"));
}
}