///|
/// Evaluation of RFC 5861 stale extensions for one stored response.
pub(all) struct StalePolicy {
is_stale : Bool
stale_by : DeltaSeconds
stale_if_error_window : DeltaSeconds?
stale_while_revalidate_window : DeltaSeconds?
stale_if_error_allowed : Bool
stale_while_revalidate_allowed : Bool
prohibited : Bool
} derive(Eq, Debug)
///|
fn minimum_optional_window(
first : DeltaSeconds?,
second : DeltaSeconds?,
) -> DeltaSeconds? {
match (first, second) {
(Some(left), Some(right)) => Some(left.min(right))
(Some(value), None) | (None, Some(value)) => Some(value)
(None, None) => None
}
}
///|
/// Evaluate origin- and client-provided stale permissions without performing
/// I/O. Explicit revalidation requirements remain stronger than extensions.
pub fn evaluate_stale_policy(
request : RequestMeta,
response : ResponseMeta,
options : CacheOptions,
now : Timestamp,
) -> StalePolicy {
let request_policy = evaluate_request_policy(request)
let request_directives = cache_control_from_headers(request.headers)
let response_directives = cache_control_from_headers(response.headers)
let age = calculate_current_age(response, now)
let freshness = calculate_freshness_lifetime(response, options)
let is_stale = age.current_age >= freshness.lifetime
let stale_by = age.current_age.saturating_sub(freshness.lifetime)
let stale_if_error_window = minimum_optional_window(
request_directives.stale_if_error,
response_directives.stale_if_error,
)
let stale_while_revalidate_window = response_directives.stale_while_revalidate
let prohibited = request_policy.bypass ||
request_policy.force_revalidation ||
request_policy.only_if_cached ||
response_directives.no_cache ||
response_directives.must_revalidate ||
(options.mode is Shared && response_directives.proxy_revalidate)
StalePolicy::{
is_stale,
stale_by,
stale_if_error_window,
stale_while_revalidate_window,
stale_if_error_allowed: is_stale &&
!prohibited &&
(match stale_if_error_window {
Some(window) => stale_by <= window
None => false
}),
stale_while_revalidate_allowed: is_stale &&
!prohibited &&
(match stale_while_revalidate_window {
Some(window) => stale_by <= window
None => false
}),
prohibited,
}
}
///|
/// RFC 5861 defines these statuses as errors eligible for stale-if-error.
pub fn is_stale_if_error_status(status : Int) -> Bool {
status == 500 || status == 502 || status == 503 || status == 504
}