This commit is contained in:
Mateusz Gruszczyński committed 2026-10-19 14:05:13 +02:00
1 parent 28e39f7ce4
commit b57beb83c7
34 files changed
+1037 -314

No files matched your search

+30 -10
View File
@@ -96,7 +96,12 @@ fn enforce_local_page_no_cache(response: &mut Response) {
.insert("cache-control", HeaderValue::from_static("no-store"));
}
fn error(status: StatusCode, message: &'static str) -> Response {
fn error(status: StatusCode, detail: &'static str) -> Response {
tracing::debug!(
status = status.as_u16(),
detail = detail.trim_end(),
"proxy generated error"
);
let mut response = if let Some(html) = crate::pages::builtin_gateway_error(status) {
let mut response = (status, html).into_response();
response.headers_mut().insert(
@@ -109,11 +114,22 @@ fn error(status: StatusCode, message: &'static str) -> Response {
);
response
} else {
(status, message).into_response()
// For statuses without a built-in error page (405, 421, 501, ...),
// emit the HTTP status instead of implementation-specific diagnostics.
let body = format!(
"{} {}\n",
status.as_u16(),
status.canonical_reason().unwrap_or("Error")
);
(status, body).into_response()
};
response
.headers_mut()
.insert("cache-control", HeaderValue::from_static("no-store"));
response.headers_mut().insert(
"x-content-type-options",
HeaderValue::from_static("nosniff"),
);
response.extensions_mut().insert(LocalGeneratedResponse);
response
}
@@ -154,10 +170,7 @@ fn encoded_origin_path(path: &str) -> Option<String> {
url.set_path(path);
Some(url.path().to_owned())
}
fn response_context(
snapshot: &crate::config::Snapshot,
request: &Request,
) -> SelectedRouteContext {
fn response_context(snapshot: &crate::config::Snapshot, request: &Request) -> SelectedRouteContext {
let tls = request
.extensions()
.get::<Transport>()
@@ -171,7 +184,9 @@ fn response_context(
let frontend = snapshot.frontend(&host, local, tls).cloned();
let path = crate::acl::routing_path_view(request.uri().path()).ok();
let route = path.as_ref().and_then(|path| {
snapshot.select_on_arc(&host, path.as_ref(), local, tls).cloned()
snapshot
.select_on_arc(&host, path.as_ref(), local, tls)
.cloned()
});
// An ordinary path borrows the original URI in forward_request. Only
// a decoded path needs to be moved between middleware and forwarding.
@@ -368,8 +383,11 @@ async fn empty_for_cache(request: &mut Request) -> Result<bool, axum::Error> {
for _ in 0..8 {
let next = if bounded_h3_navigation {
match tokio::time::timeout(
std::time::Duration::from_millis(35), request.body_mut().frame(),
).await {
std::time::Duration::from_millis(35),
request.body_mut().frame(),
)
.await
{
Ok(frame) => frame,
Err(_) => return Ok(false),
}
@@ -437,7 +455,9 @@ async fn normalize_h3_h1_unknown_body(
match tokio::time::timeout(
std::time::Duration::from_millis(35),
request.body_mut().frame(),
).await {
)
.await
{
Ok(frame) => frame,
Err(_) => return Ok(()),
}
+28
View File
@@ -713,3 +713,31 @@ mod graceful_h2_tests {
assert_eq!(backend.origin, "https://127.0.0.1:9000");
}
}
#[tokio::test]
async fn proxy_generated_error_responses_use_generic_statuses() {
use http_body_util::BodyExt;
let unsupported = error(
StatusCode::NOT_IMPLEMENTED,
"RustProxy: internal CONNECT implementation detail\n",
);
assert_eq!(unsupported.status(), StatusCode::NOT_IMPLEMENTED);
assert_eq!(unsupported.headers()["cache-control"], "no-store");
assert_eq!(
unsupported.into_body().collect().await.unwrap().to_bytes(),
"501 Not Implemented\n"
);
let not_found = error(
StatusCode::NOT_FOUND,
"RustProxy: internal routing detail\n",
);
assert_eq!(not_found.status(), StatusCode::NOT_FOUND);
assert_eq!(
not_found.headers()["content-type"],
"text/html; charset=utf-8"
);
let bytes = not_found.into_body().collect().await.unwrap().to_bytes();
let page = std::str::from_utf8(&bytes).unwrap();
assert!(page.contains("404"));
assert!(!page.contains("RustProxy: internal"));
}