v0.34.12
This commit is contained in:
1 parent
b3dfd570b5
commit
a4042d6439
16 files changed
+362
-55
No files matched your search
Vendored
+74
@@ -409,6 +409,80 @@ mod dashboard_tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rfc9211_method_bypass_and_stale_hit_do_not_misstate_freshness() {
|
||||
assert_eq!(cache_status_ttl(1, 2), -1);
|
||||
assert_eq!(cache_status_ttl(10, 10), 0);
|
||||
assert_eq!(cache_status_ttl(600, 5), 595);
|
||||
let settings = Settings {
|
||||
expose_status: true,
|
||||
expose_cache_status: true,
|
||||
..Settings::default()
|
||||
};
|
||||
let mut headers = HeaderMap::new();
|
||||
settings.annotate_reason(&mut headers, "BYPASS", 0, 0, "request_method");
|
||||
assert_eq!(
|
||||
headers["cache-status"],
|
||||
"RustProxy; fwd=method; detail=\"request_method\"",
|
||||
);
|
||||
let mut headers = HeaderMap::new();
|
||||
settings.annotate_reason_transformed_freshness(
|
||||
&mut headers, "HIT", 3, -7, "cache_max_stale", false,
|
||||
);
|
||||
assert_eq!(
|
||||
headers["cache-status"],
|
||||
"RustProxy; hit; ttl=-7; detail=\"cache_max_stale\"",
|
||||
);
|
||||
let mut headers = HeaderMap::new();
|
||||
settings.annotate_reason_transformed_freshness(
|
||||
&mut headers, "HIT", 3, -5, "cache_stale_while_revalidate", false,
|
||||
);
|
||||
assert_eq!(
|
||||
headers["cache-status"],
|
||||
"RustProxy; hit; ttl=-5; detail=\"cache_stale_while_revalidate\"",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rfc9211_forwarded_stale_error_and_forced_validation_report_real_hops() {
|
||||
let settings = Settings {
|
||||
expose_status: true,
|
||||
expose_cache_status: true,
|
||||
..Settings::default()
|
||||
};
|
||||
let mut headers = HeaderMap::new();
|
||||
headers.append("cache-status", HeaderValue::from_static("OriginCache; hit"));
|
||||
settings.annotate_reason_transformed_forwarded(
|
||||
&mut headers, "HIT", 3, 0, "cache_stale_if_error", false,
|
||||
"stale", Some(StatusCode::SERVICE_UNAVAILABLE),
|
||||
);
|
||||
assert_eq!(headers["x-cache"], "HIT");
|
||||
let values: Vec<_> = headers.get_all("cache-status").iter()
|
||||
.map(|value| value.to_str().unwrap()).collect();
|
||||
assert_eq!(values, vec![
|
||||
"OriginCache; hit",
|
||||
"RustProxy; fwd=stale; fwd-status=503; detail=\"cache_stale_if_error\"",
|
||||
]);
|
||||
let mut headers = HeaderMap::new();
|
||||
settings.annotate_reason_transformed_forwarded(
|
||||
&mut headers, "HIT", 2, 42, "cache_revalidated", false,
|
||||
"request", Some(StatusCode::NOT_MODIFIED),
|
||||
);
|
||||
assert_eq!(
|
||||
headers["cache-status"],
|
||||
"RustProxy; fwd=request; fwd-status=304; detail=\"cache_revalidated\"",
|
||||
);
|
||||
let mut headers = HeaderMap::new();
|
||||
settings.annotate_reason_transformed_forwarded(
|
||||
&mut headers, "HIT", 2, 0, "cache_stale_if_error", false,
|
||||
"stale", None,
|
||||
);
|
||||
assert_eq!(
|
||||
headers["cache-status"],
|
||||
"RustProxy; fwd=stale; detail=\"cache_stale_if_error\"",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cache_domain_metrics_do_not_lock_hot_store_and_preserve_reasons() {
|
||||
let cache = Cache::new(7);
|
||||
|
||||
Vendored
+4
@@ -52,6 +52,7 @@ impl Cache {
|
||||
transformed,
|
||||
skip_compression,
|
||||
remaining_ttl,
|
||||
entry_ttl,
|
||||
body_bytes,
|
||||
) = {
|
||||
let entry = store.entries.get_mut(&storage_key)?;
|
||||
@@ -67,6 +68,7 @@ impl Cache {
|
||||
entry.transformed,
|
||||
entry.skip_compression,
|
||||
entry.ttl.saturating_sub(age),
|
||||
entry.ttl,
|
||||
entry.body.len(),
|
||||
)
|
||||
};
|
||||
@@ -97,6 +99,7 @@ impl Cache {
|
||||
hits,
|
||||
transformed,
|
||||
remaining_ttl,
|
||||
cache_status_ttl: cache_status_ttl(entry_ttl, age),
|
||||
resident_age_seconds,
|
||||
stale: state.stale(),
|
||||
background_revalidate: state.background_revalidate(),
|
||||
@@ -301,6 +304,7 @@ impl Cache {
|
||||
hits,
|
||||
transformed: entry.transformed,
|
||||
remaining_ttl: entry.ttl.saturating_sub(age),
|
||||
cache_status_ttl: cache_status_ttl(entry.ttl, age),
|
||||
resident_age_seconds,
|
||||
stale: state.stale(),
|
||||
background_revalidate: state.background_revalidate(),
|
||||
|
||||
Vendored
+1
@@ -110,6 +110,7 @@ impl Cache {
|
||||
hits,
|
||||
transformed: cached.transformed,
|
||||
remaining_ttl,
|
||||
cache_status_ttl: cache_status_ttl(plan.ttl, age),
|
||||
resident_age_seconds: resident_age.as_secs(),
|
||||
stale: false,
|
||||
background_revalidate: false,
|
||||
|
||||
Vendored
+79
-9
@@ -171,7 +171,7 @@ impl Settings {
|
||||
.any(|item| item.eq_ignore_ascii_case(extension))
|
||||
}
|
||||
pub fn annotate(&self, headers: &mut HeaderMap, outcome: &'static str, hits: u64, ttl: u64) {
|
||||
self.annotate_internal(headers, outcome, hits, ttl, None, false);
|
||||
self.annotate_internal(headers, outcome, hits, ttl as i64, None, false, None);
|
||||
}
|
||||
|
||||
pub fn annotate_reason(
|
||||
@@ -182,7 +182,15 @@ impl Settings {
|
||||
ttl: u64,
|
||||
reason: &'static str,
|
||||
) {
|
||||
self.annotate_internal(headers, outcome, hits, ttl, Some(reason), false);
|
||||
self.annotate_internal(
|
||||
headers,
|
||||
outcome,
|
||||
hits,
|
||||
ttl as i64,
|
||||
Some(reason),
|
||||
false,
|
||||
None,
|
||||
);
|
||||
}
|
||||
|
||||
pub fn annotate_reason_transformed(
|
||||
@@ -194,7 +202,57 @@ impl Settings {
|
||||
reason: &'static str,
|
||||
transformed: bool,
|
||||
) {
|
||||
self.annotate_internal(headers, outcome, hits, ttl, Some(reason), transformed);
|
||||
self.annotate_internal(
|
||||
headers,
|
||||
outcome,
|
||||
hits,
|
||||
ttl as i64,
|
||||
Some(reason),
|
||||
transformed,
|
||||
None,
|
||||
);
|
||||
}
|
||||
|
||||
pub fn annotate_reason_transformed_freshness(
|
||||
&self,
|
||||
headers: &mut HeaderMap,
|
||||
outcome: &'static str,
|
||||
hits: u64,
|
||||
freshness_ttl: i64,
|
||||
reason: &'static str,
|
||||
transformed: bool,
|
||||
) {
|
||||
self.annotate_internal(
|
||||
headers,
|
||||
outcome,
|
||||
hits,
|
||||
freshness_ttl,
|
||||
Some(reason),
|
||||
transformed,
|
||||
None,
|
||||
);
|
||||
}
|
||||
|
||||
pub fn annotate_reason_transformed_forwarded(
|
||||
&self,
|
||||
headers: &mut HeaderMap,
|
||||
outcome: &'static str,
|
||||
hits: u64,
|
||||
ttl: u64,
|
||||
reason: &'static str,
|
||||
transformed: bool,
|
||||
forward: &'static str,
|
||||
forward_status: Option<StatusCode>,
|
||||
) {
|
||||
self.annotate_internal(
|
||||
headers,
|
||||
outcome,
|
||||
hits,
|
||||
ttl as i64,
|
||||
Some(reason),
|
||||
transformed,
|
||||
Some((forward, forward_status)),
|
||||
);
|
||||
}
|
||||
|
||||
fn annotate_internal(
|
||||
@@ -202,9 +260,10 @@ impl Settings {
|
||||
headers: &mut HeaderMap,
|
||||
outcome: &'static str,
|
||||
hits: u64,
|
||||
ttl: u64,
|
||||
ttl: i64,
|
||||
reason: Option<&'static str>,
|
||||
transformed: bool,
|
||||
forwarded: Option<(&'static str, Option<StatusCode>)>,
|
||||
) {
|
||||
if !self.enabled {
|
||||
return;
|
||||
@@ -245,15 +304,26 @@ impl Settings {
|
||||
);
|
||||
}
|
||||
if self.expose_cache_status {
|
||||
let mut value = if matches!(
|
||||
reason,
|
||||
Some("cache_revalidated" | "cache_revalidated_uncached")
|
||||
) {
|
||||
"RustProxy; fwd=stale; fwd-status=304".to_owned()
|
||||
let forwarded = forwarded.or_else(|| {
|
||||
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}");
|
||||
if let Some(status) = status {
|
||||
value.push_str(&format!("; fwd-status={}", status.as_u16()));
|
||||
}
|
||||
value
|
||||
} else {
|
||||
match outcome {
|
||||
"HIT" => format!("RustProxy; hit; ttl={ttl}"),
|
||||
"MISS" => "RustProxy; fwd=miss".to_owned(),
|
||||
"BYPASS" if reason == Some("request_method") => {
|
||||
"RustProxy; fwd=method".to_owned()
|
||||
}
|
||||
_ => "RustProxy; fwd=bypass".to_owned(),
|
||||
}
|
||||
};
|
||||
|
||||
Vendored
+15
@@ -126,12 +126,18 @@ impl Drop for ColdReadGuard<'_> {
|
||||
}
|
||||
}
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
pub struct Hit {
|
||||
pub response: Response,
|
||||
body: Bytes,
|
||||
pub hits: u64,
|
||||
pub transformed: bool,
|
||||
pub remaining_ttl: u64,
|
||||
pub cache_status_ttl: i64,
|
||||
pub resident_age_seconds: u64,
|
||||
pub stale: bool,
|
||||
pub background_revalidate: bool,
|
||||
@@ -163,6 +169,15 @@ impl Revalidation {
|
||||
pub fn reusable_without_validation(&self) -> bool {
|
||||
self.reusable_without_validation
|
||||
}
|
||||
pub fn cache_status_forward_reason(&self, request_forces_validation: bool) -> &'static str {
|
||||
if self.age >= self.ttl {
|
||||
"stale"
|
||||
} else if request_forces_validation && self.reusable_without_validation {
|
||||
"request"
|
||||
} else {
|
||||
"miss"
|
||||
}
|
||||
}
|
||||
pub fn headers(&self) -> &HeaderMap {
|
||||
&self.headers
|
||||
}
|
||||
|
||||
Vendored
+1
@@ -173,6 +173,7 @@ impl Revalidation {
|
||||
hits: self.hits,
|
||||
transformed: self.transformed,
|
||||
remaining_ttl: self.ttl.saturating_sub(self.age),
|
||||
cache_status_ttl: cache_status_ttl(self.ttl, self.age),
|
||||
stale: false,
|
||||
background_revalidate: false,
|
||||
resident_age_seconds: self.resident_age_at_lookup.as_secs(),
|
||||
|
||||
Vendored
+1
@@ -329,6 +329,7 @@ impl Cache {
|
||||
hits,
|
||||
transformed: cached.transformed,
|
||||
remaining_ttl: 0,
|
||||
cache_status_ttl: cache_status_ttl(cached.ttl, cached.age),
|
||||
resident_age_seconds: cached.resident_age_at_lookup.as_secs(),
|
||||
stale: true,
|
||||
background_revalidate: false,
|
||||
|
||||
Reference in new issue
Block a user