mirror of
https://github.com/fawney19/Aether.git
synced 2026-10-10 19:29:50 +08:00
feat(gateway): harden failover and payload handling
Retry pre-response transport failures across candidates with an explicit stop policy, and propagate end-to-end timing into usage records and UI diagnostics. Remove legacy body, import, cookie, PII, and tunnel replay caps while preserving optional operator-configured gateway limits.
This commit is contained in:
@@ -3,7 +3,7 @@ use aether_admission_core::{
|
||||
DefaultAdmissionPolicy, ResourceClass,
|
||||
};
|
||||
|
||||
use crate::{DEFAULT_OWNER_RELAY_BODY_LIMIT_BYTES, DEFAULT_TUNNEL_PROBE_BODY_LIMIT_BYTES};
|
||||
use crate::DEFAULT_TUNNEL_PROBE_BODY_LIMIT_BYTES;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum TunnelAdmissionClass {
|
||||
@@ -27,7 +27,7 @@ pub struct TunnelAdmissionPolicy {
|
||||
impl TunnelAdmissionPolicy {
|
||||
pub fn decide(&self, request: TunnelAdmissionRequest<'_>) -> AdmissionDecision {
|
||||
let body_limit = body_limit(request.class);
|
||||
if request.body_bytes > body_limit {
|
||||
if body_limit.is_some_and(|limit| request.body_bytes > limit) {
|
||||
return AdmissionDecision::Reject(AdmissionRejectReason::BodyTooLarge);
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ impl TunnelAdmissionPolicy {
|
||||
body_bytes: request.body_bytes,
|
||||
}) {
|
||||
AdmissionDecision::Admit(mut budget) => {
|
||||
budget.body_bytes = body_limit;
|
||||
budget.body_bytes = body_limit.unwrap_or(0);
|
||||
AdmissionDecision::Admit(budget)
|
||||
}
|
||||
rejected => rejected,
|
||||
@@ -45,11 +45,11 @@ impl TunnelAdmissionPolicy {
|
||||
}
|
||||
}
|
||||
|
||||
const fn body_limit(class: TunnelAdmissionClass) -> usize {
|
||||
const fn body_limit(class: TunnelAdmissionClass) -> Option<usize> {
|
||||
match class {
|
||||
TunnelAdmissionClass::Connection => 0,
|
||||
TunnelAdmissionClass::Relay { .. } => DEFAULT_OWNER_RELAY_BODY_LIMIT_BYTES,
|
||||
TunnelAdmissionClass::Probe => DEFAULT_TUNNEL_PROBE_BODY_LIMIT_BYTES,
|
||||
TunnelAdmissionClass::Connection => Some(0),
|
||||
TunnelAdmissionClass::Relay { .. } => None,
|
||||
TunnelAdmissionClass::Probe => Some(DEFAULT_TUNNEL_PROBE_BODY_LIMIT_BYTES),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ mod tests {
|
||||
use super::{TunnelAdmissionClass, TunnelAdmissionPolicy, TunnelAdmissionRequest};
|
||||
use aether_admission_core::{AdmissionDecision, AdmissionRejectReason, DbClass};
|
||||
|
||||
use crate::DEFAULT_OWNER_RELAY_BODY_LIMIT_BYTES;
|
||||
use crate::DEFAULT_TUNNEL_PROBE_BODY_LIMIT_BYTES;
|
||||
|
||||
#[test]
|
||||
fn stream_connection_reserves_stream_and_upstream_permits() {
|
||||
@@ -86,23 +86,27 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn relay_budget_exposes_and_enforces_body_limit() {
|
||||
fn relay_budget_has_no_body_limit() {
|
||||
let policy = TunnelAdmissionPolicy::default();
|
||||
let decision = policy.decide(TunnelAdmissionRequest {
|
||||
trace_id: "trace-2",
|
||||
class: TunnelAdmissionClass::Relay { streaming: false },
|
||||
body_bytes: DEFAULT_OWNER_RELAY_BODY_LIMIT_BYTES,
|
||||
body_bytes: usize::MAX,
|
||||
});
|
||||
let AdmissionDecision::Admit(budget) = decision else {
|
||||
panic!("relay at the limit should be admitted");
|
||||
panic!("relay body should be admitted without a size limit");
|
||||
};
|
||||
assert_eq!(budget.body_bytes, DEFAULT_OWNER_RELAY_BODY_LIMIT_BYTES);
|
||||
assert_eq!(budget.body_bytes, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn probe_budget_still_enforces_body_limit() {
|
||||
let policy = TunnelAdmissionPolicy::default();
|
||||
assert_eq!(
|
||||
policy.decide(TunnelAdmissionRequest {
|
||||
trace_id: "trace-3",
|
||||
class: TunnelAdmissionClass::Relay { streaming: false },
|
||||
body_bytes: DEFAULT_OWNER_RELAY_BODY_LIMIT_BYTES + 1,
|
||||
class: TunnelAdmissionClass::Probe,
|
||||
body_bytes: DEFAULT_TUNNEL_PROBE_BODY_LIMIT_BYTES + 1,
|
||||
}),
|
||||
AdmissionDecision::Reject(AdmissionRejectReason::BodyTooLarge)
|
||||
);
|
||||
|
||||
@@ -18,6 +18,6 @@ pub use hub::{
|
||||
};
|
||||
pub use relay::{
|
||||
is_tunnel_heartbeat_path, is_tunnel_node_status_path, TunnelAttachmentRecord,
|
||||
DEFAULT_OWNER_RELAY_BODY_LIMIT_BYTES, DEFAULT_TUNNEL_PROBE_BODY_LIMIT_BYTES, PROXY_TUNNEL_PATH,
|
||||
TUNNEL_HEARTBEAT_PATH, TUNNEL_NODE_STATUS_PATH, TUNNEL_RELAY_PATH_PATTERN, TUNNEL_ROUTE_FAMILY,
|
||||
DEFAULT_TUNNEL_PROBE_BODY_LIMIT_BYTES, PROXY_TUNNEL_PATH, TUNNEL_HEARTBEAT_PATH,
|
||||
TUNNEL_NODE_STATUS_PATH, TUNNEL_RELAY_PATH_PATTERN, TUNNEL_ROUTE_FAMILY,
|
||||
};
|
||||
|
||||
@@ -6,7 +6,6 @@ pub const TUNNEL_NODE_STATUS_PATH: &str = "/api/internal/tunnel/node-status";
|
||||
pub const TUNNEL_RELAY_PATH_PATTERN: &str = "/api/internal/tunnel/relay/{node_id}";
|
||||
pub const TUNNEL_ROUTE_FAMILY: &str = "tunnel_manage";
|
||||
|
||||
pub const DEFAULT_OWNER_RELAY_BODY_LIMIT_BYTES: usize = 5_242_880;
|
||||
pub const DEFAULT_TUNNEL_PROBE_BODY_LIMIT_BYTES: usize = 64 * 1024;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
|
||||
Reference in New Issue
Block a user