From bd077754a98c2737b60b99f9dc623aee8206a0eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Gruszczy=C5=84ski?= Date: Sun, 25 Oct 2026 10:19:42 +0100 Subject: [PATCH] v0.34.12 --- SHA256SUMS | 2 +- src/cache/model/entry.rs | 39 ++++++++------------------------- src/cache/model/maintenance.rs | 1 + src/proxy/forward/web_source.rs | 23 ++++++++++--------- 4 files changed, 24 insertions(+), 41 deletions(-) diff --git a/SHA256SUMS b/SHA256SUMS index 3609aa2..5e2eb5c 100644 --- a/SHA256SUMS +++ b/SHA256SUMS @@ -399,7 +399,7 @@ a6580dc359d1f377a48ccc1a902056dc5c2ef86c89180b9b0995068d9817ae8a src/proxy/forw 0e6e288fb8a0575aaa4e3bcb5c47ed5412a584386a2b00fb25db8428d652cbf3 src/proxy/forward/success_finish.rs 744daef016d4a6c821ab12eeedaa2f29e2de72e2ac9dae16481d4f43476cb713 src/proxy/forward/success_prepare.rs e9ac9be64f6f83c4ca2cd5d299649f24dd16197712083c6dc10e55c662c65b80 src/proxy/forward/upstream.rs -fcac33e29f518964e8a8d90f44f58a984cf610a5960150a0149c54425491ea86 src/proxy/forward/web_source.rs +690ff6a6860a7ca8ecd502657a68e5012b7f176036d6d7033dabc514735dc2f5 src/proxy/forward/web_source.rs 3340583d395fcc859cf3421f4e33cf8347915ee4c468f7d0e4abebce8156fdca src/proxy/forward_entry.rs 9b25f5e3ea4443a63ee6f45d12e1957dd316fe8e85325fc00ea416faaab1025a src/proxy/h2_graceful.rs 684ea1e2a7591a17e3c633576fc66e2a30d6636738fbce61dab5af44f2c51a67 src/proxy/headers/authority_tests.rs diff --git a/src/cache/model/entry.rs b/src/cache/model/entry.rs index b7d2772..813a775 100644 --- a/src/cache/model/entry.rs +++ b/src/cache/model/entry.rs @@ -182,15 +182,7 @@ impl Settings { ttl: u64, reason: &'static str, ) { - self.annotate_internal( - headers, - outcome, - hits, - ttl as i64, - Some(reason), - false, - None, - ); + self.annotate_internal(headers, outcome, hits, ttl as i64, Some(reason), false, None); } pub fn annotate_reason_transformed( @@ -202,15 +194,7 @@ impl Settings { reason: &'static str, transformed: bool, ) { - self.annotate_internal( - headers, - outcome, - hits, - ttl as i64, - Some(reason), - transformed, - None, - ); + self.annotate_internal(headers, outcome, hits, ttl as i64, Some(reason), transformed, None); } pub fn annotate_reason_transformed_freshness( @@ -223,16 +207,12 @@ impl Settings { transformed: bool, ) { self.annotate_internal( - headers, - outcome, - hits, - freshness_ttl, - Some(reason), - transformed, - None, + headers, outcome, hits, freshness_ttl, Some(reason), transformed, None, ); } + // RFC 9211 distinguishes whether this request was forwarded from whether + // the legacy X-Cache metric counted the reused representation as a HIT. pub fn annotate_reason_transformed_forwarded( &self, headers: &mut HeaderMap, @@ -305,11 +285,8 @@ impl Settings { } if self.expose_cache_status { let forwarded = forwarded.or_else(|| { - matches!( - reason, - Some("cache_revalidated" | "cache_revalidated_uncached") - ) - .then_some(("stale", Some(StatusCode::NOT_MODIFIED))) + matches!(reason, Some("cache_revalidated" | "cache_revalidated_uncached")) + .then_some(("stale", Some(StatusCode::NOT_MODIFIED))) }); let mut value = if let Some((why, status)) = forwarded { let mut value = format!("RustProxy; fwd={why}"); @@ -319,6 +296,8 @@ impl Settings { value } else { match outcome { + // RFC 9211 permits a negative ttl when stale data is served + // without sending the current request to the origin. "HIT" => format!("RustProxy; hit; ttl={ttl}"), "MISS" => "RustProxy; fwd=miss".to_owned(), "BYPASS" if reason == Some("request_method") => { diff --git a/src/cache/model/maintenance.rs b/src/cache/model/maintenance.rs index 0205626..1339a08 100644 --- a/src/cache/model/maintenance.rs +++ b/src/cache/model/maintenance.rs @@ -126,6 +126,7 @@ impl Drop for ColdReadGuard<'_> { } } } +// RFC 9211 uses signed structured-field integers for freshness (negative when stale). fn cache_status_ttl(ttl: u64, age: u64) -> i64 { const MAX: i128 = 999_999_999_999_999; (i128::from(ttl) - i128::from(age)).clamp(-MAX, MAX) as i64 diff --git a/src/proxy/forward/web_source.rs b/src/proxy/forward/web_source.rs index 2ba0dbf..d8bdd5e 100644 --- a/src/proxy/forward/web_source.rs +++ b/src/proxy/forward/web_source.rs @@ -72,12 +72,18 @@ let cached_revalidation = if let Some(ticket) = cache_ticket.as_ref() { state.cache.revalidation_tiered(ticket).await } else { None }; - let freshness_headers = crate::cache::request_freshness_headers( - &request_headers, cache_settings, - ); - let needs_validation = policy.revalidation_reason().is_some() - || cached_revalidation.as_ref().is_some_and(|cached| - !cached.reusable_for_request(&freshness_headers)); + let (needs_validation, request_forces_validation) = { + let freshness_headers = crate::cache::request_freshness_headers( + &request_headers, cache_settings, + ); + let freshness_revalidation_requested = cached_revalidation.as_ref().is_some_and(|cached| + cached.request_freshness_revalidation_reason(&freshness_headers).is_some()); + let needs_validation = policy.revalidation_reason().is_some() + || cached_revalidation.as_ref().is_some_and(|cached| + !cached.reusable_for_request(&freshness_headers)); + (needs_validation, + policy.revalidation_reason().is_some() || freshness_revalidation_requested) + }; if let Some(ticket) = &cache_ticket { if !needs_validation { if let Some(mut hit) = state.cache.get_tiered(ticket, cache_settings).await { @@ -260,10 +266,7 @@ if let Some(cached) = &cached_revalidation { cache_settings.annotate_reason_transformed_forwarded( response.headers_mut(), outcome, 0, 0, reason, transformed, - cached.cache_status_forward_reason( - policy.revalidation_reason().is_some() - || cached.request_freshness_revalidation_reason(&freshness_headers).is_some(), - ), + cached.cache_status_forward_reason(request_forces_validation), None, ); } else {