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
This commit is contained in:
gru committed 2026-11-05 18:29:56 +01:00
1 parent d3b492874b
commit eba9f89283
135 files changed
+1425 -1064

No files matched your search

+28 -17
View File
@@ -15,7 +15,7 @@ impl Predicate for MinimumSize {
fn should_compress<B: http_body::Body>(&self, response: &http::Response<B>) -> bool {
let size = response
.headers()
.get(http::header::CONTENT_LENGTH)
.get(::http::header::CONTENT_LENGTH)
.and_then(|v| v.to_str().ok())
.and_then(|v| v.parse::<u64>().ok())
.or_else(|| response.body().size_hint().exact());
@@ -147,7 +147,7 @@ impl AppliedEncoding {
pub fn no_transform(headers: &HeaderMap) -> bool {
headers
.get_all("cache-control")
.get_all(::http::header::CACHE_CONTROL)
.iter()
.filter_map(|v| v.to_str().ok())
.any(|v| {
@@ -165,9 +165,13 @@ pub fn no_transform(headers: &HeaderMap) -> bool {
pub(crate) fn request_headers(headers: &HeaderMap) -> HeaderMap {
let mut selected = HeaderMap::new();
for name in ["accept-encoding", "range", "cache-control"] {
for value in headers.get_all(name) {
selected.append(name, value.clone());
for name in [
::http::header::ACCEPT_ENCODING,
::http::header::RANGE,
::http::header::CACHE_CONTROL,
] {
for value in headers.get_all(&name) {
selected.append(name.clone(), value.clone());
}
}
selected
@@ -185,10 +189,14 @@ fn eligible(
|| response.status().is_informational()
|| response.status().as_u16() == 204
|| response.status().as_u16() == 304
|| response.headers().contains_key("content-encoding")
|| response.headers().contains_key("content-range")
|| response.headers().contains_key("upgrade")
|| request.contains_key("range")
|| response
.headers()
.contains_key(::http::header::CONTENT_ENCODING)
|| response
.headers()
.contains_key(::http::header::CONTENT_RANGE)
|| response.headers().contains_key(::http::header::UPGRADE)
|| request.contains_key(::http::header::RANGE)
|| no_transform(request)
|| no_transform(response.headers())
{
@@ -196,7 +204,7 @@ fn eligible(
}
!response
.headers()
.get("content-type")
.get(::http::header::CONTENT_TYPE)
.and_then(|v| v.to_str().ok())
.is_some_and(|v| {
v.split(';')
@@ -221,7 +229,7 @@ pub(crate) fn preferred_encoding(
) -> Option<AppliedEncoding> {
let mut explicit = [None; 4];
let mut wildcard = None;
for line in headers.get_all("accept-encoding").iter() {
for line in headers.get_all(::http::header::ACCEPT_ENCODING).iter() {
let Ok(line) = line.to_str() else { continue };
for item in line.split(',') {
let mut parts = item.split(';');
@@ -304,17 +312,20 @@ pub async fn encode(
let mut request = Request::new(Body::empty());
*request.method_mut() = method.clone();
request.headers_mut().insert(
"accept-encoding",
::http::header::ACCEPT_ENCODING,
HeaderValue::from_static(selected.as_str()),
);
let mut response = match compression.oneshot(request).await {
Ok(response) => response.map(Body::new),
Err(never) => match never {},
};
if response.headers().contains_key("content-encoding") {
if response
.headers()
.contains_key(::http::header::CONTENT_ENCODING)
{
if let Some(applied) = response
.headers()
.get("content-encoding")
.get(::http::header::CONTENT_ENCODING)
.and_then(|value| value.to_str().ok())
.and_then(AppliedEncoding::from_header)
{
@@ -322,15 +333,15 @@ pub async fn encode(
}
if let Some(value) = response
.headers()
.get("etag")
.get(::http::header::ETAG)
.and_then(|v| v.to_str().ok())
.map(str::to_owned)
{
if !value.starts_with("W/") {
if let Ok(weak) = HeaderValue::from_str(&format!("W/{value}")) {
response.headers_mut().insert("etag", weak);
response.headers_mut().insert(::http::header::ETAG, weak);
} else {
response.headers_mut().remove("etag");
response.headers_mut().remove(::http::header::ETAG);
}
}
}