v0.35.1: performance, AGPL licensing and documentation overhaul

- Web Server reads static files inline; proxy middleware chain flattened
- About window with license summary and project links; AGPL-3.0-or-later
- Rewritten documentation: feature list, screenshots, performance guide
- Fix false spikes in per-Vhost request-rate charts

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MMsgSXoK4Bph2vU6fSBkAH
This commit is contained in:
Claude committed 2026-11-05 18:29:56 +01:00
1 parent d3b492874b
commit d40c30d0e8
135 files changed
+1425 -1064

No files matched your search

+13 -20
View File
@@ -61,9 +61,9 @@ pub fn plan(
return None;
}
if status != StatusCode::OK
|| headers.contains_key("set-cookie")
|| headers.contains_key("content-range")
|| headers.contains_key("trailer")
|| headers.contains_key(::http::header::SET_COOKIE)
|| headers.contains_key(::http::header::CONTENT_RANGE)
|| headers.contains_key(::http::header::TRAILER)
{
return None;
}
@@ -75,7 +75,7 @@ pub fn plan(
return None;
}
if headers
.get("content-type")
.get(::http::header::CONTENT_TYPE)
.and_then(|v| v.to_str().ok())
.is_some_and(|v| {
let v = v.trim_start().to_ascii_lowercase();
@@ -92,14 +92,11 @@ pub fn plan(
{
return None;
}
// Surrogate-Control: no-store is a shared-cache veto in compatibility
// mode, regardless of public/fallback TTL or any other directive.
// Surrogate-Control: no-store always vetoes shared caching.
if settings.varnish_compatible && surrogate_no_store(headers) {
return None;
}
// Explicitly configured fallback TTL is an opt-in origin no-cache
// override *only* for public responses. With fallback disabled, keep
// the pre-0.34.7 validator-based revalidation and never grant a HIT.
// Fallback TTL overrides origin no-cache only for public responses.
let override_public_no_cache = settings.varnish_compatible
&& control.contains_key("no-cache")
&& control.contains_key("public")
@@ -117,13 +114,13 @@ pub fn plan(
let mut stale_while_revalidate = parse_window("stale-while-revalidate")?;
let stale_if_error = parse_window("stale-if-error")?;
if requires_revalidation
&& !headers.contains_key("etag")
&& !headers.contains_key("last-modified")
&& !headers.contains_key(::http::header::ETAG)
&& !headers.contains_key(::http::header::LAST_MODIFIED)
{
return None;
}
let now = SystemTime::now();
let date = match headers.get("date") {
let date = match headers.get(::http::header::DATE) {
Some(v) => httpdate::parse_http_date(v.to_str().ok()?).ok()?,
None => now,
};
@@ -131,7 +128,7 @@ pub fn plan(
Some(settings.default_ttl_seconds)
} else if let Some(value) = control.get("s-maxage").or_else(|| control.get("max-age")) {
Some(value.as_ref()?.parse::<u64>().ok()?)
} else if let Some(expires) = headers.get("expires") {
} else if let Some(expires) = headers.get(::http::header::EXPIRES) {
Some(
httpdate::parse_http_date(expires.to_str().ok()?)
.ok()?
@@ -144,7 +141,7 @@ pub fn plan(
} else {
None
};
let age = match headers.get("age") {
let age = match headers.get(::http::header::AGE) {
Some(v) => v.to_str().ok()?.parse::<u64>().ok()?,
None => 0,
};
@@ -161,11 +158,7 @@ pub fn plan(
None if requires_revalidation => 0,
None => return None,
};
// Retain zero-TTL and already-expired representations for conditional
// revalidation, client max-stale or stale-if-error. They must not be
// served as fresh HITs. Varnish-style grace is only implicit when the
// origin did not explicitly set stale-while-revalidate (including =0),
// the object arrived fresh and no origin no-cache rule is in effect.
// Expired entries are kept for revalidation only; implicit grace needs no explicit SWR/no-cache.
if settings.varnish_compatible
&& !control.contains_key("stale-while-revalidate")
&& !control.contains_key("no-cache")
@@ -184,7 +177,7 @@ pub fn plan(
{
return None;
}
let expected_length = match headers.get("content-length") {
let expected_length = match headers.get(::http::header::CONTENT_LENGTH) {
Some(v) => Some(v.to_str().ok()?.parse::<usize>().ok()?),
None => None,
};