This commit is contained in:
Mateusz Gruszczyński committed 2026-10-06 23:54:01 +02:00
1 parent 9d6614c1b4
commit a9f9450f80
16 files changed
+171 -47

No files matched your search

+36 -15
View File
@@ -31,6 +31,7 @@ pub struct CompiledRule {
op: Operation,
name: HeaderName,
value: Option<HeaderValue>,
wire_only: bool,
}
#[derive(Debug, Clone, Default)]
pub struct CompiledHeaders {
@@ -43,16 +44,20 @@ impl HeaderRules {
}
pub fn compile(&self) -> Result<CompiledHeaders> {
Ok(CompiledHeaders {
request: compile_rules(&self.request)?,
response: compile_rules(&self.response)?,
request: compile_rules(&self.request, Direction::Request)?,
response: compile_rules(&self.response, Direction::Response)?,
})
}
}
#[derive(Clone, Copy, PartialEq, Eq)]
enum Direction {
Request,
Response,
}
fn protected(name: &str) -> bool {
matches!(
name,
"host"
| "age"
| "connection"
| "content-length"
| "transfer-encoding"
@@ -74,7 +79,7 @@ fn protected(name: &str) -> bool {
) || name.starts_with("x-forwarded-")
|| name.starts_with("sec-websocket-")
}
fn compile_rules(rules: &[Rule]) -> Result<Vec<CompiledRule>> {
fn compile_rules(rules: &[Rule], direction: Direction) -> Result<Vec<CompiledRule>> {
ensure!(
rules.len() <= 32,
"at most 32 header rules per direction and scope"
@@ -102,23 +107,39 @@ fn compile_rules(rules: &[Rule]) -> Result<Vec<CompiledRule>> {
op: rule.op,
name,
value,
wire_only: direction == Direction::Response
&& rule.name.eq_ignore_ascii_case("age"),
})
})
.collect()
}
fn apply_rule(headers: &mut HeaderMap, rule: &CompiledRule) {
match (&rule.op, &rule.value) {
(Operation::Remove, _) => {
headers.remove(&rule.name);
}
(Operation::Set, Some(value)) => {
headers.insert(rule.name.clone(), value.clone());
}
(Operation::Append, Some(value)) => {
headers.append(rule.name.clone(), value.clone());
}
_ => unreachable!("only compiled header rules reach the request path"),
}
}
pub fn apply(headers: &mut HeaderMap, rules: &[CompiledRule]) {
for rule in rules {
match (&rule.op, &rule.value) {
(Operation::Remove, _) => {
headers.remove(&rule.name);
}
(Operation::Set, Some(value)) => {
headers.insert(rule.name.clone(), value.clone());
}
(Operation::Append, Some(value)) => {
headers.append(rule.name.clone(), value.clone());
}
_ => unreachable!("only compiled header rules reach the request path"),
// Response Age rules are a wire-only presentation override. Applying
// them here would let a configured value enter cache freshness/storage.
if !rule.wire_only {
apply_rule(headers, rule);
}
}
}
pub fn apply_wire_age(headers: &mut HeaderMap, rules: &[CompiledRule]) {
for rule in rules {
if rule.wire_only {
apply_rule(headers, rule);
}
}
}