133 lines
5.5 KiB
Rust
133 lines
5.5 KiB
Rust
{
|
|
match upstream_result {
|
|
Ok(Ok(mut response)) => {
|
|
if let Some(fallback) = execute_error_fallback(
|
|
state.clone(), peer, local, &snapshot, &host, tls, route,
|
|
response.status(), &fallback_request, &fallback_body,
|
|
).await {
|
|
return fallback;
|
|
}
|
|
let (origin_validation_headers, origin_plan, origin_reason, mut response) =
|
|
include!("success_prepare.rs");
|
|
include!("success_finish.rs")
|
|
}
|
|
Ok(Err(cause)) => {
|
|
if let Some(session) = h2_direct_session.take() {
|
|
session.cancellation().cancel();
|
|
}
|
|
let elapsed = upstream_started.elapsed();
|
|
let connect_failure = cause.is_connect();
|
|
let detail = upstream_failure_detail(&cause, &active_backend, elapsed, connect_failure);
|
|
let failure_class =
|
|
upstream_health_error_class(&cause, connect_failure, &active_backend);
|
|
let graceful_h2_close = matches!(
|
|
failure_class,
|
|
"h2_graceful_goaway" | "h2_graceful_close"
|
|
);
|
|
if let Some(exchange) = &exchange {
|
|
exchange.websocket_error("upstream_request_failed", "upstream_http_error");
|
|
*exchange.upstream_error.lock().unwrap_or_else(|e| e.into_inner()) = Some(detail.clone());
|
|
}
|
|
if let Some(lease) = &active_lease {
|
|
lease.error_detail(failure_class, &detail, final_attempt_elapsed);
|
|
}
|
|
if connect_failure {
|
|
tracing::warn!(
|
|
backend = %active_backend.id,
|
|
origin = %active_backend.origin,
|
|
request_origin = %active_backend.request_origin,
|
|
tls_verify = active_backend.tls_verify,
|
|
elapsed_ms = elapsed.as_millis(),
|
|
error = %detail,
|
|
"upstream connection failed"
|
|
);
|
|
} else if graceful_h2_close {
|
|
tracing::trace!(
|
|
backend = %active_backend.id,
|
|
origin = %active_backend.origin,
|
|
elapsed_ms = elapsed.as_millis(),
|
|
error = %detail,
|
|
"upstream H2 graceful close left an unrecovered request"
|
|
);
|
|
} else {
|
|
tracing::debug!(
|
|
backend = %active_backend.id,
|
|
origin = %active_backend.origin,
|
|
elapsed_ms = elapsed.as_millis(),
|
|
error = %detail,
|
|
"upstream HTTP request failed"
|
|
);
|
|
}
|
|
let status = if connect_failure {
|
|
StatusCode::SERVICE_UNAVAILABLE
|
|
} else {
|
|
StatusCode::BAD_GATEWAY
|
|
};
|
|
let stale_class = classify_stale_error(&cause);
|
|
if cache_settings.allows_stale_error_class(stale_class) {
|
|
if let Some(stale) = serve_stale("cache_stale_if_error", elapsed, &active_backend.id, None) {
|
|
return stale;
|
|
}
|
|
}
|
|
if let Some(fallback) = execute_error_fallback(
|
|
state.clone(), peer, local, &snapshot, &host, tls, route,
|
|
status, &fallback_request, &fallback_body,
|
|
).await {
|
|
return fallback;
|
|
}
|
|
let mut response = error(
|
|
status,
|
|
if status == StatusCode::SERVICE_UNAVAILABLE {
|
|
"RustProxy: upstream unavailable (DNS, TCP or TLS connection failed)\n"
|
|
} else {
|
|
"RustProxy: upstream did not provide a valid HTTP response\n"
|
|
},
|
|
);
|
|
response
|
|
.headers_mut()
|
|
.insert("cache-control", HeaderValue::from_static("no-store"));
|
|
if status == StatusCode::SERVICE_UNAVAILABLE {
|
|
response
|
|
.headers_mut()
|
|
.insert("retry-after", HeaderValue::from_static("1"));
|
|
}
|
|
response
|
|
}
|
|
Err(_) => {
|
|
if let Some(session) = h2_direct_session.take() {
|
|
session.cancellation().cancel();
|
|
}
|
|
if let Some(exchange) = &exchange {
|
|
exchange.websocket_error("upstream_timeout", "header_timeout");
|
|
*exchange.upstream_error.lock().unwrap_or_else(|e| e.into_inner()) = Some("response_header_timeout".into());
|
|
}
|
|
if let Some(lease) = &active_lease {
|
|
lease.error_detail(
|
|
"response_header_timeout",
|
|
"response_header_timeout",
|
|
final_attempt_elapsed,
|
|
);
|
|
}
|
|
if cache_settings
|
|
.allows_stale_error_class(crate::cache::StaleErrorClass::Timeout)
|
|
{
|
|
if let Some(stale) =
|
|
serve_stale("cache_stale_if_error", upstream_started.elapsed(), &active_backend.id, None)
|
|
{
|
|
return stale;
|
|
}
|
|
}
|
|
if let Some(fallback) = execute_error_fallback(
|
|
state.clone(), peer, local, &snapshot, &host, tls, route,
|
|
StatusCode::GATEWAY_TIMEOUT, &fallback_request, &fallback_body,
|
|
).await {
|
|
return fallback;
|
|
}
|
|
error(
|
|
StatusCode::GATEWAY_TIMEOUT,
|
|
"RustProxy: upstream response deadline exceeded\n",
|
|
)
|
|
}
|
|
}
|
|
}
|