This commit is contained in:
Mateusz Gruszczyński committed 2026-10-08 22:22:46 +02:00
1 parent 76cb4acef0
commit 68678e98be
84 files changed
+1519 -325

No files matched your search

+43 -15
View File
@@ -2,6 +2,15 @@ async fn forward(
State(state): State<Arc<App>>,
Extension(peer): Extension<PeerAddr>,
Extension(local): Extension<LocalAddr>,
request: Request,
) -> Response {
forward_request(state, peer, local, request).await
}
async fn forward_request(
state: Arc<App>,
peer: PeerAddr,
local: LocalAddr,
mut request: Request,
) -> Response {
if request.method() == Method::CONNECT
@@ -88,6 +97,10 @@ async fn forward(
.get::<Arc<crate::config::Snapshot>>()
.cloned()
.unwrap_or_else(|| state.config.load_full());
let internal_dispatch = request
.extensions()
.get::<InternalFallbackRoute>()
.cloned();
let Ok(path) = crate::acl::routing_path(request.uri().path()) else {
return error(
StatusCode::BAD_REQUEST,
@@ -226,21 +239,23 @@ async fn forward(
"RustProxy: denied by access policy\n",
);
}
if let Err(limited) = state.rate_limiter.check(
snapshot.envelope.revision,
&frontend.id,
context.client_ip,
country.as_deref(),
&frontend.rate_limit,
) {
let mut response = error(
StatusCode::TOO_MANY_REQUESTS,
"RustProxy: request rate limit exceeded\n",
);
if let Ok(value) = HeaderValue::from_str(&limited.retry_after_seconds.to_string()) {
response.headers_mut().insert("retry-after", value);
if internal_dispatch.is_none() {
if let Err(limited) = state.rate_limiter.check(
snapshot.envelope.revision,
&frontend.id,
context.client_ip,
country.as_deref(),
&frontend.rate_limit,
) {
let mut response = error(
StatusCode::TOO_MANY_REQUESTS,
"RustProxy: request rate limit exceeded\n",
);
if let Ok(value) = HeaderValue::from_str(&limited.retry_after_seconds.to_string()) {
response.headers_mut().insert("retry-after", value);
}
return response;
}
return response;
}
}
// Global host ACLs remain an independent restrictive scope and also apply to
@@ -272,7 +287,15 @@ async fn forward(
});
return response;
}
let selected = snapshot.select_on(&host, &path, local.0, tls);
let selected = if let Some(dispatch) = &internal_dispatch {
if frontend.is_none_or(|frontend| frontend.id != dispatch.vhost_id) {
None
} else {
snapshot.select_internal_on(&host, &dispatch.vhost_id, &dispatch.target, local.0, tls)
}
} else {
snapshot.select_on(&host, &path, local.0, tls)
};
if let Some(route) = selected {
if let Some(response) = method_policy_denial(&route.method_policy, request.method()) {
return response;
@@ -306,6 +329,7 @@ async fn forward(
);
}
}
let fallback_request = ErrorFallbackRequest::capture(&request, &snapshot);
// The admin cookie is never ordinary application state. Strip it BEFORE
// auth/cache and keep only the removed fragment locally. A verified self-admin
// backend may restore it after the actual upstream has been selected.
@@ -374,6 +398,10 @@ async fn forward(
)
});
};
let fallback_body = match prepare_error_fallback_body(&mut request, route.error_fallback.is_some()).await {
Ok(body) => body,
Err(response) => return response,
};
let (
backend,
backend_lease,