This commit is contained in:
Mateusz Gruszczyński committed 2026-10-13 01:34:42 +02:00
1 parent 101df02a5f
commit bb025dcf44
27 files changed
+541 -85

No files matched your search

+52 -2
View File
@@ -68,7 +68,15 @@
let range = crate::cache::request_range(&request_method, &request_headers);
let if_range = request_headers.get("if-range").cloned();
let range_requested = !matches!(range, crate::cache::RangeSelection::None);
let needs_validation = policy.revalidation_reason().is_some();
// Unlike the original Web Server path, retain stale and client-forced
// revalidation candidates. A local 304 can refresh them without replacing
// the cached body or resetting X-Cache-Hits (same as Reverse Proxy).
let cached_revalidation = if let Some(ticket) = cache_ticket.as_ref() {
state.cache.revalidation_tiered(ticket).await
} else { None };
let needs_validation = policy.revalidation_reason().is_some()
|| cached_revalidation.as_ref().is_some_and(|cached|
!cached.reusable_for_request(&request_headers));
if let Some(ticket) = &cache_ticket {
if !needs_validation {
if let Some(mut hit) = state.cache.get_tiered(ticket, cache_settings).await {
@@ -114,9 +122,12 @@
// Neither the Request nor the streaming Body is held across a borrowed
// await: the filesystem/PHP source owns the body for its full lifetime.
let static_body = std::mem::replace(request.body_mut(), Body::empty());
let (origin_request_headers, revalidation_sent) =
web_cache_revalidation::web_origin_request_headers(
&request_headers, cached_revalidation.as_ref());
let started = Instant::now();
let response = crate::web_server::serve(service, request_method.clone(),
request_headers.clone(), request_uri, &service_path, static_body,
origin_request_headers, request_uri, &service_path, static_body,
crate::web_server::RequestContext {
client_ip: context.client_ip,
client_port: Some(peer.0.port()),
@@ -131,6 +142,45 @@
).await { return fallback; }
let mut response = intercept_route_origin_error(response, route, &snapshot);
if revalidation_sent && response.status() == StatusCode::NOT_MODIFIED {
if let (Some(ticket), Some(cached)) =
(cache_ticket.as_ref(), cached_revalidation.as_ref())
{
let revalidated = web_cache_revalidation::finish_web_revalidation(
&state.cache, ticket, cached, response.headers(), cache_settings,
started.elapsed(), &request_headers, &request_method,
ignore_cookie, force_cache,
|headers| apply_response_rules(headers, &snapshot,
route.frontend.as_deref(), Some(route), false),
);
if let Some(mut hit) = revalidated {
state.cache.record(scope, &host, "HIT", hit.reason);
if hit.transformed { state.transform_metrics.record_cache_hit(scope); }
if let Some(exchange) = request.extensions().get::<Arc<Exchange>>() {
exchange.cache_status.store(1, Ordering::Relaxed);
*exchange.cache_reason.lock().unwrap_or_else(|e| e.into_inner()) = hit.reason;
}
hit.response.extensions_mut().insert(ResponseRulesApplied);
hit.response.extensions_mut().insert(StaticSourceResponse);
return intercept_route_origin_error(hit.response, route, &snapshot);
}
// A simultaneous PURGE/config change invalidated the ticket. Do
// not accidentally return an origin 304 without a reusable body.
return error(StatusCode::SERVICE_UNAVAILABLE,
"RustProxy: Web Server cache entry invalidated during revalidation\n");
}
}
if cached_revalidation.is_some() && response.status() != StatusCode::NOT_MODIFIED
&& response.status().as_u16() < 500
{
// A changed response (including a 206, 404 or an uncacheable 200)
// supersedes the old object. Also discard when the old entry has no
// validators and therefore must be fetched unconditionally. A complete
// cacheable GET below can refill the entry.
if let Some(ticket) = cache_ticket.as_ref() {
state.cache.discard(ticket);
}
}
let origin_headers = response.headers().clone();
let original_plan = crate::cache::plan(response.status(), &origin_headers,
cache_settings, started.elapsed());