Skip to content

Commit 38ab3b6

Browse files
committed
Harden Wasm cache policy key handling
1 parent 5f68124 commit 38ab3b6

13 files changed

Lines changed: 436 additions & 26 deletions

File tree

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ behavior when the change improves security or project direction.
2121
response-header exposure.
2222
- Add live listener tests proving separate mobile and desktop cache variants
2323
MISS independently and HIT the original variant on repeat.
24+
- Add live listener tests proving Wasm-selected cache-key components isolate
25+
fixed-slice range-cache objects for ranged responses.
2426
- Add live listener tests proving a plugin TTL override expires an otherwise
2527
longer-lived origin response.
2628
- Add live listener tests proving fixed stored response-header metadata appears
@@ -35,11 +37,16 @@ behavior when the change improves security or project direction.
3537

3638
- Reject unknown cache-key component IDs, unknown values, duplicate labels, and
3739
component counts above the hard cap through the plugin fail mode.
40+
- Enforce duplicate-label rejection and the aggregate component cap across the
41+
full `cache-lookup` hook chain.
3842
- Reject unknown TTL IDs, duplicate TTL overrides, unknown tag IDs, and tag
3943
counts above the hard cap through the plugin fail mode.
4044
- Reject unknown stored-header IDs, duplicate stored-header mutations, and
4145
stored-header mutation counts above the hard cap through the plugin fail
4246
mode.
47+
- Scope cache-store tag and stored-header mutation caps independently, and
48+
reject oversized cache-store candidates before cloning response bodies for
49+
stored-header metadata.
4350
- Keep arbitrary request headers, raw cache-key bytes, request bodies, cached
4451
objects, arbitrary TTLs, arbitrary tag strings, arbitrary response-header
4552
inspection, and arbitrary stored response headers unavailable in this slice.

crates/fluxheim-server/src/native_http1_proxy_load_balanced.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,14 @@ impl NativeHttp1Proxy {
9999
}
100100
}
101101
if proxy_cache_status.is_none()
102-
&& let Some(slice) = cache.slice_response(&request, self).await
102+
&& let Some(slice) = cache
103+
.slice_response(
104+
&request,
105+
self,
106+
#[cfg(feature = "wasm")]
107+
&wasm_cache_key_components,
108+
)
109+
.await
103110
{
104111
return self.finish_response(
105112
&request,

crates/fluxheim-server/src/native_http1_proxy_memory_cache/lookup.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -98,10 +98,6 @@ impl NativeProxyMemoryCache {
9898
}
9999
}
100100

101-
pub(super) fn key(&self, request: &NativeHttp1Request) -> Option<String> {
102-
self.key_with_components(request, &[])
103-
}
104-
105101
pub(super) fn key_with_components(
106102
&self,
107103
request: &NativeHttp1Request,

crates/fluxheim-server/src/native_http1_proxy_memory_cache/slice.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ use crate::native_http1_proxy_cache_slice::{
1414
native_slice_cache_key, native_slice_identity, native_slice_not_satisfiable_response,
1515
native_slice_object_from_entry, native_slice_request_within_policy,
1616
};
17+
#[cfg(feature = "wasm")]
18+
use crate::native_http1_proxy_memory_cache::NativeProxyCacheKeyComponent;
1719
use crate::{NativeHttp1Request, NativeHttp1Response};
1820
use fluxheim_cache::{
1921
CacheRequestView, CacheSliceBounds, request_cache_bypass_reason, resolve_client_slice_ranges,
@@ -27,17 +29,24 @@ impl NativeProxyMemoryCache {
2729
&self,
2830
request: &NativeHttp1Request,
2931
proxy: &NativeHttp1Proxy,
32+
#[cfg(feature = "wasm")] key_components: &[NativeProxyCacheKeyComponent],
3033
) -> Option<NativeCacheSliceResponse> {
3134
if !self.config.range.enabled || !self.config.range.slice.enabled {
3235
return None;
3336
}
37+
let base_key = self.key_with_components(
38+
request,
39+
#[cfg(feature = "wasm")]
40+
key_components,
41+
#[cfg(not(feature = "wasm"))]
42+
&[],
43+
)?;
3444
if request_cache_bypass_reason(request, &self.config).is_some()
35-
|| self.cache_pass_should_bypass(&self.key(request)?)
45+
|| self.cache_pass_should_bypass(&base_key)
3646
{
3747
return None;
3848
}
3949
let slice_request = selected_cache_slice_range_request(request, &self.config)?;
40-
let base_key = self.key(request)?;
4150
let slice_size = self.config.range.slice.size_bytes.as_u64();
4251
let (total, first_slice, first_filled) = self
4352
.discover_slice_total(&base_key, request, proxy, slice_size)

crates/fluxheim-server/src/native_http1_proxy_memory_cache/store.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -198,17 +198,17 @@ impl NativeProxyMemoryCache {
198198
mode: NativeCacheStoreMode,
199199
metadata: NativeProxyCacheStoreMetadata,
200200
) -> Result<(), &'static str> {
201+
let body_len = response.body().len() as u64;
202+
if body_len > self.config.max_object_bytes.as_u64() {
203+
return Err("object-too-large");
204+
}
201205
let stored_response;
202206
let response = if metadata.response_headers.is_empty() {
203207
response
204208
} else {
205209
stored_response = native_cache_store_response_with_metadata(response, &metadata);
206210
&stored_response
207211
};
208-
let body_len = response.body().len() as u64;
209-
if body_len > self.config.max_object_bytes.as_u64() {
210-
return Err("object-too-large");
211-
}
212212
let headers = native_response_header_map(response);
213213
let vary_fields = match cache_vary_policy(&headers, &self.config) {
214214
VaryCachePolicy::None => None,

crates/fluxheim-server/src/native_http1_proxy_static_dispatch.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,14 @@ impl NativeHttp1Proxy {
9292
}
9393
}
9494
if proxy_cache_status.is_none()
95-
&& let Some(slice) = cache.slice_response(&request, self).await
95+
&& let Some(slice) = cache
96+
.slice_response(
97+
&request,
98+
self,
99+
#[cfg(feature = "wasm")]
100+
&wasm_cache_key_components,
101+
)
102+
.await
96103
{
97104
return self.finish_response(
98105
&request,

0 commit comments

Comments
 (0)