0.34.6_repo_cleanup
This commit is contained in:
1 parent
ce1a90397c
commit
133d2f0f91
273 files changed
+5969
-6926
No files matched your search
Vendored
+1
-24
@@ -28,9 +28,7 @@ pub struct ObjectView {
|
||||
pub storage_bytes: u64,
|
||||
pub tier: &'static str,
|
||||
pub hits: u64,
|
||||
/// RFC 9111 Age, including time before the object entered this cache.
|
||||
pub age_seconds: u64,
|
||||
/// Total time held by RustProxy HOT/COLD; excludes any upstream CDN Age.
|
||||
pub resident_age_seconds: u64,
|
||||
pub remaining_ttl_seconds: u64,
|
||||
}
|
||||
@@ -50,11 +48,8 @@ pub struct Dashboard {
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct ColdCleanupRequest {
|
||||
/// Remove objects not used for at least this many seconds.
|
||||
pub unused_for_seconds: Option<u64>,
|
||||
/// Additionally remove up to N oldest matching objects.
|
||||
pub oldest: Option<usize>,
|
||||
/// Limit the selection to objects which were never served.
|
||||
pub hits_zero: bool,
|
||||
}
|
||||
impl Default for ColdCleanupRequest {
|
||||
@@ -113,7 +108,6 @@ struct Entry {
|
||||
created_at: SystemTime,
|
||||
headers: Arc<HeaderMap>,
|
||||
body: Bytes,
|
||||
/// Backing allocation retained by `body`; can exceed `body.len()`.
|
||||
body_allocated: usize,
|
||||
received: Instant,
|
||||
last_access: Instant,
|
||||
@@ -135,7 +129,7 @@ struct Entry {
|
||||
requires_revalidation: bool,
|
||||
}
|
||||
|
||||
#[allow(clippy::ptr_arg)] // String/Vec capacity is intentionally part of HOT accounting.
|
||||
#[allow(clippy::ptr_arg)]
|
||||
fn hot_entry_cost(
|
||||
body_allocated: usize,
|
||||
headers: &HeaderMap,
|
||||
@@ -150,11 +144,6 @@ fn hot_entry_cost(
|
||||
origin_etag: Option<&HeaderValue>,
|
||||
origin_last_modified: Option<&HeaderValue>,
|
||||
) -> usize {
|
||||
// The public containers do not expose an exact per-entry allocator charge.
|
||||
// Account their retained index memory conservatively: HOT HashMap key/control,
|
||||
// the LRU BTreeMap item/node share and the variants index (including spare
|
||||
// Vec<Key> capacity). This keeps `max_bytes` closer to the real retained
|
||||
// allocation instead of pretending Entry/body are the only HOT owners.
|
||||
let index_heap = std::mem::size_of::<Key>()
|
||||
.saturating_add(std::mem::size_of::<(u64, Key)>())
|
||||
.saturating_add(32)
|
||||
@@ -171,8 +160,6 @@ fn hot_entry_cost(
|
||||
let header_heap = headers
|
||||
.iter()
|
||||
.map(|(name, value)| {
|
||||
// HeaderMap does not expose its bucket capacity. Charge a conservative
|
||||
// per-field bucket/node allowance in addition to visible name/value bytes.
|
||||
name.as_str()
|
||||
.len()
|
||||
.saturating_add(value.as_bytes().len())
|
||||
@@ -181,7 +168,6 @@ fn hot_entry_cost(
|
||||
.sum::<usize>();
|
||||
body_allocated
|
||||
.saturating_add(std::mem::size_of::<Entry>())
|
||||
// Arc<HeaderMap> owns the actual map on a separate allocation.
|
||||
.saturating_add(std::mem::size_of::<HeaderMap>())
|
||||
.saturating_add(2 * std::mem::size_of::<usize>())
|
||||
.saturating_add(index_heap)
|
||||
@@ -207,7 +193,6 @@ struct ColdFile {
|
||||
#[serde(default)]
|
||||
vary: Vec<String>,
|
||||
revision: u64,
|
||||
/// 0 denotes legacy/unscoped entries; production vhosts require an exact match.
|
||||
#[serde(default)]
|
||||
scope_revision: u64,
|
||||
scope: String,
|
||||
@@ -284,9 +269,6 @@ struct ColdEntry {
|
||||
hits: u64,
|
||||
transformed: bool,
|
||||
sequence: u64,
|
||||
// Stable identity of this in-memory cold entry. Unlike `sequence`, this
|
||||
// never changes on access, so an old async reader cannot unpin a newer
|
||||
// replacement stored under the same cache key.
|
||||
generation: u64,
|
||||
skip_compression: bool,
|
||||
requires_revalidation: bool,
|
||||
@@ -311,8 +293,6 @@ struct ColdDraft {
|
||||
key_generation: u64,
|
||||
entry: Entry,
|
||||
root: PathBuf,
|
||||
/// Keeps this full in-memory object charged to the bounded transient pool
|
||||
/// until the COLD write completes and the payload is dropped.
|
||||
_memory_lease: TransientLease,
|
||||
}
|
||||
|
||||
@@ -331,8 +311,6 @@ struct Store {
|
||||
sequence: u64,
|
||||
generation: u64,
|
||||
revision: u64,
|
||||
/// Current persisted administrative config revision. Distinct from cache
|
||||
/// representation revision: operational saves do not evict data.
|
||||
control_revision: u64,
|
||||
scope_generations: HashMap<String, u64>,
|
||||
key_generations: HashMap<Key, u64>,
|
||||
@@ -361,7 +339,6 @@ impl Store {
|
||||
Some(entry)
|
||||
}
|
||||
fn next_sequence(&mut self) -> u64 {
|
||||
// No practical wrapping, but a wrap must not corrupt LRU bookkeeping.
|
||||
if self.sequence == u64::MAX {
|
||||
self.entries.clear();
|
||||
self.variants.clear();
|
||||
|
||||
Vendored
+20
-24
@@ -167,7 +167,6 @@ impl Settings {
|
||||
.any(|item| item.eq_ignore_ascii_case(extension))
|
||||
}
|
||||
pub fn annotate(&self, headers: &mut HeaderMap, outcome: &'static str, hits: u64, ttl: u64) {
|
||||
// Origin values must never masquerade as this proxy's diagnostics.
|
||||
for name in [
|
||||
"x-cache",
|
||||
"x-cache-hits",
|
||||
@@ -178,15 +177,15 @@ impl Settings {
|
||||
] {
|
||||
headers.remove(name);
|
||||
}
|
||||
// A vhost that explicitly disables cache must look like a normal reverse proxy.
|
||||
// Keep counters internally, but never expose cache diagnostics for that response.
|
||||
if !self.enabled {
|
||||
return;
|
||||
}
|
||||
if let Some(value) = &self.via_header {
|
||||
headers.append(
|
||||
http::header::VIA,
|
||||
value.parse::<HeaderValue>().expect("validated cache Via header"),
|
||||
value
|
||||
.parse::<HeaderValue>()
|
||||
.expect("validated cache Via header"),
|
||||
);
|
||||
}
|
||||
if self.expose_only_hits && outcome != "HIT" {
|
||||
@@ -226,10 +225,15 @@ impl Settings {
|
||||
}
|
||||
}
|
||||
pub fn annotate_transformed(&self, headers: &mut HeaderMap, transformed: bool) {
|
||||
if !self.enabled || !self.expose_cache_status || !transformed
|
||||
|| (self.expose_only_hits && !headers.get("cache-status")
|
||||
.and_then(|value| value.to_str().ok())
|
||||
.is_some_and(|value| value.starts_with("RustProxy; hit"))) {
|
||||
if !self.enabled
|
||||
|| !self.expose_cache_status
|
||||
|| !transformed
|
||||
|| (self.expose_only_hits
|
||||
&& !headers
|
||||
.get("cache-status")
|
||||
.and_then(|value| value.to_str().ok())
|
||||
.is_some_and(|value| value.starts_with("RustProxy; hit")))
|
||||
{
|
||||
return;
|
||||
}
|
||||
let base = headers
|
||||
@@ -246,7 +250,6 @@ impl Settings {
|
||||
headers.insert("cache-status", value);
|
||||
}
|
||||
}
|
||||
/// Reasons are fixed internal tokens: never echo request values or secrets.
|
||||
pub fn annotate_reason(
|
||||
&self,
|
||||
headers: &mut HeaderMap,
|
||||
@@ -284,8 +287,6 @@ fn valid_relative_cache_path(value: &str) -> bool {
|
||||
.all(|part| matches!(part, Component::Normal(_)))
|
||||
}
|
||||
|
||||
/// Explicit, per-vhost-only request-side cache override. It never weakens the
|
||||
/// response-side privacy guards (Set-Cookie/private/no-store/Vary rules).
|
||||
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct UnsafeForce {
|
||||
@@ -294,7 +295,10 @@ pub struct UnsafeForce {
|
||||
}
|
||||
impl UnsafeForce {
|
||||
pub fn validate(&self) -> Result<()> {
|
||||
ensure!(self.targets.len() <= 32, "forced cache supports at most 32 target prefixes");
|
||||
ensure!(
|
||||
self.targets.len() <= 32,
|
||||
"forced cache supports at most 32 target prefixes"
|
||||
);
|
||||
for target in &self.targets {
|
||||
ensure!(
|
||||
!target.is_empty()
|
||||
@@ -305,7 +309,10 @@ impl UnsafeForce {
|
||||
"forced cache targets must be 1..2048 byte origin-form path/query prefixes"
|
||||
);
|
||||
let path = target.split('?').next().unwrap_or(target);
|
||||
ensure!(crate::acl::routing_path(path)? == path, "forced cache target path must be normalized");
|
||||
ensure!(
|
||||
crate::acl::routing_path(path)? == path,
|
||||
"forced cache target path must be normalized"
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -323,8 +330,6 @@ impl UnsafeForce {
|
||||
}
|
||||
}
|
||||
|
||||
/// Per-vhost behavior, not independent memory pools. None inherits the global
|
||||
/// default; the global resident-byte/entry/object ceilings remain hard limits.
|
||||
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct Overrides {
|
||||
@@ -341,15 +346,12 @@ pub struct Overrides {
|
||||
pub expose_cache_status: Option<bool>,
|
||||
pub expose_resident_age: Option<bool>,
|
||||
pub expose_only_hits: Option<bool>,
|
||||
/// Deliberately unavailable in the global cache configuration.
|
||||
pub unsafe_force: UnsafeForce,
|
||||
}
|
||||
impl Overrides {
|
||||
pub fn resolve(&self, global: &Settings) -> Result<Settings> {
|
||||
self.unsafe_force.validate()?;
|
||||
let mut result = global.clone();
|
||||
// A vhost may narrow the global policy, but can never re-enable a cache
|
||||
// that the administrator disabled globally.
|
||||
result.enabled = global.enabled && self.enabled.unwrap_or(true);
|
||||
if let Some(value) = self.default_ttl_seconds {
|
||||
result.default_ttl_seconds = value;
|
||||
@@ -444,7 +446,6 @@ pub struct View {
|
||||
pub hot_eviction_limited: u64,
|
||||
pub purges: u64,
|
||||
pub entries: usize,
|
||||
/// Compatibility alias for HOT allocated/charged bytes.
|
||||
pub resident_bytes: usize,
|
||||
pub hot_logical_bytes: usize,
|
||||
pub hot_allocated_bytes: usize,
|
||||
@@ -474,16 +475,11 @@ pub struct View {
|
||||
pub proactive_skipped: u64,
|
||||
pub proactive_inflight: u64,
|
||||
pub fills_active: usize,
|
||||
/// Bytes currently allocated by in-progress response cache fills.
|
||||
pub fill_bytes_active: u64,
|
||||
/// Demoted objects accepted by the bounded cold-writer queue.
|
||||
pub cold_queue_items: u64,
|
||||
pub cold_queue_bytes: u64,
|
||||
/// Body bytes currently owned by the cold writer after leaving the queue.
|
||||
pub cold_write_bytes_active: u64,
|
||||
/// Full cold bodies currently read into RAM for promotion.
|
||||
pub cold_read_bytes_active: u64,
|
||||
/// RustProxy-accounted cache RAM outside the published hot store.
|
||||
pub transient_bytes: u64,
|
||||
pub hit_ratio: f64,
|
||||
}
|
||||
|
||||
Vendored
+10
-5
@@ -1,11 +1,11 @@
|
||||
// A strict, human-editable IP/CIDR policy. The caller supplies only a client IP
|
||||
// produced by the existing forwarding trust boundary, never an arbitrary header.
|
||||
fn parse_invalidation_cidr(value: &str) -> anyhow::Result<ipnet::IpNet> {
|
||||
let value = value.trim();
|
||||
if let Ok(ip) = value.parse::<std::net::IpAddr>() {
|
||||
return Ok(ipnet::IpNet::from(ip));
|
||||
}
|
||||
value.parse::<ipnet::IpNet>().map_err(|_| anyhow::anyhow!("invalid HTTP invalidation IP/CIDR: {value}"))
|
||||
value
|
||||
.parse::<ipnet::IpNet>()
|
||||
.map_err(|_| anyhow::anyhow!("invalid HTTP invalidation IP/CIDR: {value}"))
|
||||
}
|
||||
impl Settings {
|
||||
fn validate_http_invalidation_allowlist(&self) -> anyhow::Result<()> {
|
||||
@@ -17,7 +17,10 @@ impl Settings {
|
||||
for input in &self.http_invalidation_allowed_cidrs {
|
||||
ensure!(input.len() <= 64, "HTTP invalidation address too long");
|
||||
let net = parse_invalidation_cidr(input)?;
|
||||
ensure!(net.prefix_len() > 0, "HTTP invalidation cannot authorize the entire Internet");
|
||||
ensure!(
|
||||
net.prefix_len() > 0,
|
||||
"HTTP invalidation cannot authorize the entire Internet"
|
||||
);
|
||||
ensure!(networks.insert(net), "duplicate HTTP invalidation IP/CIDR");
|
||||
}
|
||||
Ok(())
|
||||
@@ -25,7 +28,9 @@ impl Settings {
|
||||
pub fn permits_http_invalidation(&self, client: std::net::IpAddr) -> bool {
|
||||
let client = crate::vhost::canonical_ip(client);
|
||||
self.http_invalidation_allowed_cidrs.iter().any(|value| {
|
||||
parse_invalidation_cidr(value).ok().is_some_and(|network| network.contains(&client))
|
||||
parse_invalidation_cidr(value)
|
||||
.ok()
|
||||
.is_some_and(|network| network.contains(&client))
|
||||
})
|
||||
}
|
||||
}
|
||||
Vendored
+5
-9
@@ -7,8 +7,6 @@ impl ColdStore {
|
||||
}
|
||||
fn next_sequence(&mut self) -> u64 {
|
||||
if self.sequence == u64::MAX {
|
||||
// Practically unreachable. Prefer dropping the in-memory index over
|
||||
// risking ambiguous LRU ordering after wrap.
|
||||
self.lru.clear();
|
||||
self.entries.clear();
|
||||
self.variants.clear();
|
||||
@@ -56,7 +54,6 @@ pub struct Cache {
|
||||
revision: AtomicU64,
|
||||
cold: Arc<Mutex<ColdStore>>,
|
||||
tier_settings: Mutex<Settings>,
|
||||
/// Per-vhost content compatibility used by persisted COLD metadata.
|
||||
scope_revisions: Mutex<HashMap<String, u64>>,
|
||||
data_root: Option<PathBuf>,
|
||||
cold_tx: Option<mpsc::Sender<ColdCommand>>,
|
||||
@@ -143,8 +140,6 @@ pub struct Revalidation {
|
||||
headers: HeaderMap,
|
||||
body: Bytes,
|
||||
body_allocated: usize,
|
||||
// COLD revalidation bodies remain charged to transient RAM until every
|
||||
// cloned revalidation handle is dropped or promoted. HOT revalidations use none.
|
||||
_transient_leases: Vec<TransientLease>,
|
||||
hits: u64,
|
||||
transformed: bool,
|
||||
@@ -171,9 +166,6 @@ impl Revalidation {
|
||||
&self.headers
|
||||
}
|
||||
pub fn apply_validators(&self, headers: &mut HeaderMap) -> bool {
|
||||
// Client validators refer to the representation RustProxy served. If that
|
||||
// representation was transformed, translate a matching validator back to
|
||||
// the origin validator rather than leaking the generated proxy ETag upstream.
|
||||
if headers.contains_key("if-none-match") {
|
||||
let Some(public_etag) = self.headers.get("etag").and_then(|v| v.to_str().ok()) else {
|
||||
return false;
|
||||
@@ -349,7 +341,11 @@ fn hot_resident_age(entry: &Entry) -> Duration {
|
||||
}
|
||||
|
||||
fn matching_hot_key(store: &Store, ticket: &Ticket) -> Option<Key> {
|
||||
if store.entries.get(&ticket.key).is_some_and(|entry| entry.vary.is_empty()) {
|
||||
if store
|
||||
.entries
|
||||
.get(&ticket.key)
|
||||
.is_some_and(|entry| entry.vary.is_empty())
|
||||
{
|
||||
return Some(ticket.key);
|
||||
}
|
||||
store
|
||||
|
||||
Vendored
+5
-59
@@ -24,8 +24,6 @@ const FILL_SLOTS: usize = 8;
|
||||
const COLD_DELETE_FALLBACKS: usize = 2;
|
||||
const COLD_CLEANUP_SLOTS: usize = 1;
|
||||
const BACKGROUND_REVALIDATION_LIMIT: usize = 8;
|
||||
// Cold writes can contain complete response bodies. Keep the queue deliberately
|
||||
// small so demotion cannot become a second, hidden RAM cache while disk is slow.
|
||||
const COLD_QUEUE: usize = 16;
|
||||
const COLD_FORMAT_VERSION: u8 = 3;
|
||||
type Key = [u8; 32];
|
||||
@@ -43,10 +41,6 @@ struct CleanupCandidate {
|
||||
key: Key,
|
||||
}
|
||||
|
||||
/// `Bytes` releases its allocation when the last reference is dropped, but
|
||||
/// glibc can keep large freed arenas mapped. After bulk cache demotions/purges,
|
||||
/// return releasable pages to the OS instead of letting RSS stay artificially
|
||||
/// high. This is intentionally a no-op on other allocators/platforms.
|
||||
fn release_allocator_memory() {
|
||||
#[cfg(all(target_os = "linux", target_env = "gnu"))]
|
||||
unsafe {
|
||||
@@ -93,81 +87,44 @@ pub enum ColdPreset {
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct Settings {
|
||||
pub enabled: bool,
|
||||
/// UI sizing profile last explicitly selected by the administrator. The
|
||||
/// actual numeric limits remain authoritative; this only preserves intent
|
||||
/// across reloads so the dashboard can show which preset was applied.
|
||||
pub memory_preset: Option<MemoryPreset>,
|
||||
/// Hard RAM budget for published HOT entries, charged by backing allocation
|
||||
/// plus directly owned metadata rather than only logical body length.
|
||||
pub max_bytes: usize,
|
||||
/// Maximum logical size of a single cacheable object body.
|
||||
pub max_object_bytes: usize,
|
||||
/// Hot tier object count.
|
||||
pub max_entries: usize,
|
||||
/// Bounded Varnish-style transient RAM used by in-progress fills and full
|
||||
/// bodies moving between HOT and COLD. This is independent of `max_bytes`.
|
||||
pub transient_max_bytes: usize,
|
||||
/// Byte ceiling for demoted objects waiting in the COLD writer queue.
|
||||
pub cold_queue_max_bytes: usize,
|
||||
/// Maximum number of LRU objects removed during one admission attempt.
|
||||
/// Reaching the limit makes the new object pass through uncached.
|
||||
pub hot_eviction_max_objects: usize,
|
||||
/// Automatically release idle HOT objects once the tier is above the target waterline.
|
||||
pub hot_auto_trim_enabled: bool,
|
||||
/// Minimum idle age before automatic HOT trimming can evict an object.
|
||||
pub hot_auto_trim_after_seconds: u64,
|
||||
/// Target HOT usage percentage reached by each automatic trim pass.
|
||||
pub hot_auto_trim_target_percent: u8,
|
||||
/// Persistent cold tier. Disabled by default to avoid implicit disk writes.
|
||||
pub cold_enabled: bool,
|
||||
/// Last explicitly selected COLD policy profile, persisted with the cache
|
||||
/// configuration for the same reason as `memory_preset`.
|
||||
pub cold_preset: Option<ColdPreset>,
|
||||
/// Relative to the RustProxy data directory.
|
||||
pub cold_path: String,
|
||||
pub cold_max_bytes: u64,
|
||||
pub cold_max_entries: usize,
|
||||
/// Interval between asynchronous cold-cache GC checks.
|
||||
pub cold_gc_interval_seconds: u64,
|
||||
/// Maximum number of objects removed by one GC pass.
|
||||
pub cold_gc_max_delete: usize,
|
||||
/// Hot objects not touched for this long are demoted to disk.
|
||||
pub cold_after_seconds: u64,
|
||||
/// Demote objects which have been idle for `cold_after_seconds`.
|
||||
pub cold_on_idle: bool,
|
||||
/// Demote objects after this much continuous residency in the hot tier
|
||||
/// when `cold_on_age` is enabled, even when they are still being read.
|
||||
pub cold_max_hot_seconds: u64,
|
||||
/// Apply `cold_max_hot_seconds` as a separate hot-tier age policy.
|
||||
pub cold_on_age: bool,
|
||||
/// Preserve objects evicted from the hot LRU in the cold tier.
|
||||
pub cold_on_lru: bool,
|
||||
/// Best-effort flush of hot objects to cold storage on graceful shutdown.
|
||||
pub cold_on_shutdown: bool,
|
||||
/// Only used for responses explicitly marked public and without origin TTL.
|
||||
pub default_ttl_seconds: u64,
|
||||
pub max_ttl_seconds: u64,
|
||||
pub bypass_query: bool,
|
||||
pub bypass_prefixes: Vec<String>,
|
||||
/// Actual client IP/CIDR allowlist for HTTP BAN/PURGE. Empty disables these
|
||||
/// public-listener methods (independent of authenticated admin API).
|
||||
pub http_invalidation_allowed_cidrs: Vec<String>,
|
||||
/// For explicitly selected static extensions, ignore request Cookie when
|
||||
/// deciding cache eligibility and when building the shared cache key.
|
||||
pub static_ignore_cookies: bool,
|
||||
pub static_extensions: Vec<String>,
|
||||
/// Collapse concurrent foreground cache MISS/revalidation fills for the same public cache key.
|
||||
pub collapse_enabled: bool,
|
||||
/// Maximum time a follower waits for the current fill before applying the configured fallback.
|
||||
pub collapse_wait_timeout_ms: u64,
|
||||
pub collapse_timeout_fallback: CollapseTimeoutFallback,
|
||||
/// Fine-grained stale-if-error classes. Defaults preserve the 0.21 behavior.
|
||||
pub stale_if_error_timeout: bool,
|
||||
pub stale_if_error_connection: bool,
|
||||
pub stale_if_error_dns: bool,
|
||||
pub stale_if_error_tls: bool,
|
||||
pub stale_if_error_statuses: Vec<u16>,
|
||||
/// Schedule bounded validator refresh before normal freshness expires.
|
||||
pub proactive_refresh_enabled: bool,
|
||||
pub proactive_refresh_before_expiry_seconds: u64,
|
||||
pub proactive_refresh_percent: u8,
|
||||
@@ -176,10 +133,7 @@ pub struct Settings {
|
||||
pub expose_hits: bool,
|
||||
pub expose_cache_status: bool,
|
||||
pub expose_resident_age: bool,
|
||||
/// Emit cache diagnostics only for actual HIT responses, not MISS or BYPASS.
|
||||
pub expose_only_hits: bool,
|
||||
/// Optional response Via field value added by RustProxy cache handling.
|
||||
/// `None` disables the header; the default is `Via: RustProxy`.
|
||||
pub via_header: Option<String>,
|
||||
}
|
||||
impl Default for Settings {
|
||||
@@ -214,21 +168,13 @@ impl Default for Settings {
|
||||
bypass_query: false,
|
||||
bypass_prefixes: Vec::new(),
|
||||
http_invalidation_allowed_cidrs: Vec::new(),
|
||||
// Static assets are normally representation-identical for logged-in and
|
||||
// anonymous visitors. Keep this enabled by default once the shared cache
|
||||
// itself is enabled; response-side privacy guards still reject Set-Cookie,
|
||||
// private/no-store and Vary: Cookie before anything is stored.
|
||||
static_ignore_cookies: true,
|
||||
static_extensions: vec![
|
||||
// styles / scripts
|
||||
"css", "js", "mjs", "cjs", "wasm", // images
|
||||
"png", "jpg", "jpeg", "jfif", "jxl", "gif", "webp", "avif", "apng", "svg", "ico",
|
||||
"cur", "bmp", "tif", "tiff", "heic", "heif", // fonts
|
||||
"woff", "woff2", "ttf", "otf", "eot", // video
|
||||
"mp4", "webm", "ogv", "mov", "m4v", // audio
|
||||
"mp3", "ogg", "oga", "wav", "m4a", "aac", "flac", "opus",
|
||||
// common static downloads
|
||||
"pdf", "txt", "zip", "gz", "tgz", "bz2", "xz", "7z", "rar", "tar",
|
||||
"css", "js", "mjs", "cjs", "wasm", "png", "jpg", "jpeg", "jfif", "jxl", "gif",
|
||||
"webp", "avif", "apng", "svg", "ico", "cur", "bmp", "tif", "tiff", "heic", "heif",
|
||||
"woff", "woff2", "ttf", "otf", "eot", "mp4", "webm", "ogv", "mov", "m4v", "mp3",
|
||||
"ogg", "oga", "wav", "m4a", "aac", "flac", "opus", "pdf", "txt", "zip", "gz",
|
||||
"tgz", "bz2", "xz", "7z", "rar", "tar",
|
||||
]
|
||||
.into_iter()
|
||||
.map(str::to_owned)
|
||||
|
||||
Vendored
-5
@@ -73,11 +73,6 @@ fn retention_deadline(
|
||||
_stale_if_error: u64,
|
||||
_has_validator: bool,
|
||||
) -> u64 {
|
||||
// Freshness and storage retention are deliberately separate. Expiry only
|
||||
// changes whether an object can be served without validation; it must not
|
||||
// physically evict the representation because a later request may carry
|
||||
// Cache-Control: max-stale. Capacity/LRU and Cold Cache GC remain the
|
||||
// mechanisms that decide how long an otherwise valid object is retained.
|
||||
u64::MAX
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user