v0.34.7
This commit is contained in:
1 parent
133d2f0f91
commit
3ea00045bf
27 files changed
+446
-136
No files matched your search
@@ -1,6 +1,6 @@
|
||||
# RustProxy source and documentation maintenance
|
||||
|
||||
Current source version: **0.34.6**. The Cargo package and binary are named `rust-proxy`.
|
||||
Current source version: **0.34.7**. The Cargo package and binary are named `rust-proxy`.
|
||||
|
||||
Before editing, read [README.md](README.md), [ROADMAP.md](ROADMAP.md), the relevant [documentation guide](docs/README.md) and the actual code and tests. Historical release experiments are not current specifications. Use the bundled `src/admin/openapi.json` for API routes and payloads; the source implementation is authoritative for runtime behavior.
|
||||
|
||||
|
||||
+9
-1
@@ -6,7 +6,15 @@
|
||||
|
||||
# Changelog
|
||||
|
||||
Release history focused on **features, settings, default behavior, compatibility and fixes**. Changes to internal code structure and preliminary performance experiments are intentionally omitted. Historical descriptions reflect their respective releases; consult the current documentation for the settings available in 0.34.6.
|
||||
Release history focused on **features, settings, default behavior, compatibility and fixes**. Changes to internal code structure and preliminary performance experiments are intentionally omitted. Historical descriptions reflect their respective releases; consult the current documentation for the settings available in 0.34.7.
|
||||
|
||||
## 0.34.7 — Varnish-compatible cache lookup (source candidate)
|
||||
|
||||
- **Settings → Cache → Varnish-compatible cache policy (`varnish_compatible`): ON by default**, including for existing configurations without the new field. OFF preserves the legacy stricter interpretation of incoming `Cache-Control` and `Pragma`; the toggle is applied live (no service restart), invalidates existing cache entries for storage-policy safety, and affects both reverse-proxy and embedded Web Server cache, HOT and COLD.
|
||||
- Varnish-style lookup ignores client `no-cache`, `no-store`, `max-age`, `min-fresh`, `max-stale`, `only-if-cached` and `Pragma` **only as cache control signals**; it does not remove request headers from forwarding, Vary keying, downstream conditions or user identity. Hard reloads of a fresh asset remain `HIT`, retaining `Age` and counters instead of refetching without origin validators.
|
||||
- For **origin responses**, default-compatible mode rejects `Cache-Control: no-cache`, `Surrogate-Control: no-store`, and responses with no remaining TTL. Previously protected `private`, `no-store`, `Set-Cookie`, Authorization, Vary and all explicit RustProxy cookie exceptions remain intact; an eligible stale object may be served during up to 10 seconds of background-refresh grace unless RustProxy's stronger revalidation restrictions apply.
|
||||
- Scope deliberately excludes full Varnish/VCL or hit-for-miss emulation and the 120-second implicit origin TTL default; RustProxy keeps its configured default TTL and existing safety limits. To compare live behavior, enable diagnostic headers and inspect `Age`, `X-Cache`, `X-Cache-Hits` and `X-Cache-Reason` before/after hard reload.
|
||||
- **Delivery:** source candidate, requiring native Rust compilation, integration and production acceptance tests before deployment. No binary release is claimed.
|
||||
|
||||
## 0.34.6 — Docker live logs, neutral Publish switch and Vhost Content-Type rules (source candidate)
|
||||
|
||||
|
||||
Generated
+1
-1
@@ -1881,7 +1881,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rust-proxy"
|
||||
version = "0.34.6"
|
||||
version = "0.34.7"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"arc-swap",
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "rust-proxy"
|
||||
version = "0.34.6"
|
||||
version = "0.34.7"
|
||||
edition = "2021"
|
||||
rust-version = "1.99"
|
||||
description = "RustProxy - independent reverse proxy with local administration"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# RustProxy 0.34.6
|
||||
# RustProxy 0.34.7
|
||||
|
||||
RustProxy combines a reverse proxy, static/PHP web server, certificate management and traffic monitoring in one service with a browser administration panel. It supports several domains and backends without requiring a separate proxy configuration language.
|
||||
|
||||
@@ -16,6 +16,10 @@ RustProxy combines a reverse proxy, static/PHP web server, certificate managemen
|
||||
|
||||
Features and default settings vary by component; configure only the capabilities you need. The [documentation index](docs/README.md) covers each workflow, including prerequisites, security boundaries, troubleshooting and API access.
|
||||
|
||||
## 0.34.7
|
||||
|
||||
- **Settings → Cache:** Varnish-compatible cache policy (on by default), with legacy strict semantics when disabled. Prevents client hard-reloads from needlessly refilling still-fresh HOT/COLD objects; respects origin cache privacy and preserves RustProxy static-cookie handling. See [Cache](docs/CACHE.md) for the scope and important exceptions.
|
||||
|
||||
## 0.34.6
|
||||
|
||||
- **Docker vhosts:** **Live logs** beside **Open app** opens the existing HTTP access-log viewer, filtered to the selected generated Docker vhost and its aliases. These are RustProxy request logs, not container stdout/stderr. Open app honors HTTPS and nonstandard listener ports.
|
||||
@@ -95,4 +99,4 @@ The authenticated **`/docs`** page includes the guides and a separate interactiv
|
||||
|
||||
## Status of this source archive
|
||||
|
||||
Version **0.34.6** is provided as a **source release candidate**. Configuration, ACL and TLS changes require native compilation and integration testing on the target systems before a production deployment is declared. See [Installation](docs/INSTALL.md) and [Roadmap](ROADMAP.md).
|
||||
Version **0.34.7** is provided as a **source release candidate**. Configuration, ACL and TLS changes require native compilation and integration testing on the target systems before a production deployment is declared. See [Installation](docs/INSTALL.md) and [Roadmap](ROADMAP.md).
|
||||
+100
-110
@@ -1,12 +1,12 @@
|
||||
61bf40a0572889dc8b0dda9eae4e93e44b0de9364b3c798106c85700ffb37c23 .dockerignore
|
||||
4140a2956264b44f259e6a37fc00ba02097bbe68b09296e04d3d243c1287129b .env.example
|
||||
9e6356475bf587091bab72246ec9e325b498f7e48a6220e9a18baa50d0a385a6 .gitignore
|
||||
893ba606f52309e31b3d0612350a9cdeb36d0414325bc06e71e2f7ce15e755cb AGENTS.md
|
||||
72dc91c90b524db7571a8916a4409d0faad41fafc4da14987eecc396adc63290 CHANGELOG.md
|
||||
4865f5f0a9cbc64899b70acc0f6ad328bbfa40560a78d39874e4b9563d2f56b9 Cargo.lock
|
||||
fbba365b98bfc31b891d8ef240270b76987d67778b4d795552069e6b94f3f9ea Cargo.toml
|
||||
10e5382f535df61cc2e5905d83a61d40ac3e60572e7ff8e05bad6271d871b6c5 AGENTS.md
|
||||
d88bcb686fed1626510867d9b44a9db4e6020a65e9c2369ced781e5744f64022 CHANGELOG.md
|
||||
32a192c94173ec66cce81890c71f235febeda7cf59bc8581fc982e1a0759b296 Cargo.lock
|
||||
82922877469166aff8eec6805e56f9c7f07b95dba2dc02d17c9c9fd5f39747fa Cargo.toml
|
||||
25c7f3c8162cbf5cc156439774118a81dae9fdc52b611ec7e40c230fc99a772c Dockerfile
|
||||
fcd1ace66c47e43e13b8cfadd76a9ae02ad545af944fa684c489034227776432 README.md
|
||||
626f18ec4028ae66ec4b65eb8dab83405e568d64396a3e58d25a247851fecb90 README.md
|
||||
ae6d14ada6fde7d0b8514840b821678418cf5b1816c18434e3b7fb2ae27a0b21 ROADMAP.md
|
||||
da8311e3db945290666324a2f24bf4521b365272d7ac3f862ded1be993eea646 UPDATE_CHECK.toml
|
||||
7309cfaa188c7a1fcf30be1b8313ee99c00b7fe5d6d626ddefcc7345fa066112 build.rs
|
||||
@@ -32,8 +32,8 @@ e52b31d0abf65ae3034f6cb367cca113633014ce8d1d799ad4dd5624d2c7b8bb docker-agent/n
|
||||
9268ab7fe86683dacd64bafbd9e0edc8956ce9b9ef6277cc6ada61c3fcb84746 docs/API.md
|
||||
2362ab34020d4e0dcd70e280e9539ef7764b63212856ee08a3a55906c48f6421 docs/API_ACCESS.md
|
||||
728b15b9825f547f34c4121219784798dd046fbbdd72ece8906d0cd77e8efc64 docs/BACKUP.md
|
||||
0305f4e464cae51d50ed6a171571515505aab3bc3aacdcfaa632f252460cd4a8 docs/CACHE.md
|
||||
c81c6ee84e6af6507926144f8caf1e94daf497a8a0159449a3808088a11ea045 docs/CONFIGURATION.md
|
||||
e072271ddba43e3759b9ea7702c41a8357d13008f8b664c62fa860eadf2f1e1e docs/CACHE.md
|
||||
c3f4cb4e32d90a2f334d864cc3fb051f6a7d662f37daa554a8988530b6dec56f docs/CONFIGURATION.md
|
||||
80bcc666736b10f6202386d0342e8d6feeba858d77aea310bf3ec6de01c2bfb3 docs/CONTAINER.md
|
||||
dc670d912a6a946160c2f8528c9bb710ec38ebe406dcb7dcaf18fb2653f667b6 docs/CUSTOM_LOCATIONS.md
|
||||
9fb2d0bcac70d1883dd16557622851a1f0527b3d3569a4b5177f5e6dedd3c74d docs/DASHBOARD.md
|
||||
@@ -44,7 +44,7 @@ f1baabe34e8a1b204d7c78e2f558c019c156b03adfa6ddecb931b4b8a5501f78 docs/INSTALL.m
|
||||
888cdc8c56e10b8a7615012e192e085bf2899d0ec9b3ddfb5731e7de6ab5bcde docs/MIGRATION.md
|
||||
140b95ad778261455f269f2144a1c61c2315bd3b85300fb613822eacddf3cfc2 docs/MONITORING.md
|
||||
d5894c07c68ec4230987767198434abee13b0e525842fea21bcbe752fa82742b docs/PHP_FPM.md
|
||||
f72a94114558f15341842352146c1743f79bb1f7fbca3b93b7ca89368a398961 docs/README.md
|
||||
6af7d306dc32ad03408a4bafcb819f7ef430fcc34fdbea460504483fea31b84f docs/README.md
|
||||
490a6dbe870f2b1fd4ec7816768dde6c86fa7957fc9de2d2f075e123c9222222 docs/RESPONSE_DELIVERY.md
|
||||
e2b36152c13d65621a367c69dd400118dae1e4426a4d2b2139d2f63fa30442d6 docs/SECURITY.md
|
||||
bbef60ff1771da9f48af812987766e1e479408873ae2f079b13f1d5c62ecc6ff docs/STREAMS.md
|
||||
@@ -76,8 +76,8 @@ cb01fdef286f38b442dd9252c23c4f8e44eb72e9ecdd99adb926e8e9f6318bb1 integrations/r
|
||||
96563a83e87cfb33e238c2a970ce36b1a1b51e91318d09b123c3755002ba2646 integrations/routeros-oci-build/build-routeros-oci.sh
|
||||
3f267cafa16006e5456ade78ee2d5fae02cc7ce747839523068ffd8d7c98798a integrations/routeros-oci-build/docker-entrypoint.sh
|
||||
13189fa546c3488dddd8efc80c47f6da5241e5fc28b79cbfe795414ea05c7a4f langs/README.md
|
||||
7eb29175875efda638783d2c802eac176364a9e6c156df8960ab1f1099f366ef langs/en_US.json
|
||||
00dab018f5548e87b790ecbdad700aa01a595c6d5f439d61d146e84b0acf2a06 langs/pl_pl.json
|
||||
d08c2f6ea2abc0fc848300c2bfd911885863de81bceda533d10991cc55a93e97 langs/en_US.json
|
||||
1cf4e525442e65e6007c54304197e71853b8991d9a5990dfdae6e72b1de389e1 langs/pl_pl.json
|
||||
a99ad040be10fa028351e290b9363236b3513a1cadbdc9fb9e0260d517b9b0ae make_zip.py
|
||||
e830d37dd1f81a4b0aa7d535f5bba69e34e433b0fd99cc8ee0b296786c32379a migrations/0002_admin.sql
|
||||
20112cc82192098b8d602f1c4f7ca08712e9e1366c845fabb92753187c370d35 migrations/0003_certificate_renewals.sql
|
||||
@@ -98,7 +98,7 @@ ee50f38c037765fab742e888d4b9fc4d874c31c785c6064d4eca3d2c4d24d944 nagios/check_r
|
||||
7458b2d74495e6fb1c1edeea4d5a793705476431dadb60627187111f91441e13 rust-toolchain.toml
|
||||
bd313cacfc1b450a90368b30ae39ab48b877c8bed3c2db8bbd4e4a1f40865c9e scripts/README.md
|
||||
f550ffab868c5241ff5d43d9ae569e19f6842b324b80ecefdc7034642125ed9b scripts/audit_css_usage.py
|
||||
31953ddf3fda1c9b47fb5de7f85b91a23782b4ccc9555b8423a965659a0a8786 scripts/build/swagger_assets.py
|
||||
216abccbb8b0b77b28de96382bb5790d1ce831699746d3fb06ef13a6dd1f5d21 scripts/build/swagger_assets.py
|
||||
e4d15aa6aa864d04b9b30aca33826b833632af02ca643f8b23e219a5ea1298dd scripts/deploy/deploy.py
|
||||
618603239b000bbe4af36a6a6ee268758af632c761fc53fc6b7f44a4a818bdf1 scripts/deploy/deploy_core.py
|
||||
8c7da13e95bcddd2bd1b4f1b22ade1c5ac1ecf54448601daa8416905d4239751 scripts/deploy/deploy_runtime.py
|
||||
@@ -106,7 +106,7 @@ a641bd35400c56f3b68b0a92e97b602d06090f03972ca8f01fa744e90dd97403 scripts/deploy
|
||||
2cc658faaa610b21b48942c59b955525539ad4503fd60f2a49c7e626a22faaff scripts/migration/migrate_npm.py
|
||||
a459d95bbb0076f33ade8b273b813308167f9d8d45242b309a2d18320ca0093c scripts/migration/migrate_npm_api.py
|
||||
31ccad3ec3c880119f3b7002f0c6652f8b43634edad8ab3763cb0e4497d0bb1f scripts/migration/migrate_npm_core.py
|
||||
91c5ab0f82af5a4eb5589f5ebb19975f053eacaa46fa3d59b74f3ddde6370562 scripts/preflight.py
|
||||
3077405aae2dd0f32c0e168ef710745bd44e42283a4c566ab411e68d3bb745af scripts/preflight.py
|
||||
3d6a0503afc25beab79ddc86864bcbb15248ded7368d33aa64321b8cdff59933 scripts/resolve_dependencies_0312.sh
|
||||
20124173452b4514bad8850c1637569a9a191882478451e549bd16b432605fc1 scripts/runtime/acme_provider.py
|
||||
e69813fb1d3a4cdcfb7243964cc323fc21a603087bf2e84188fa42b9d3cee4b5 scripts/runtime/acme_rfc2136.py
|
||||
@@ -123,43 +123,43 @@ b9eff08fddf9b8787aa04e72288ea2ca0033965e4563d060ca51f267e4963918 src/acme/jobs.
|
||||
f7f737aa28d2d209f4f20a221885e3bb3596dfc8e3c8c9a22ba53bb975c52df8 src/acme/model.rs
|
||||
40cd44f2b0d43ba45471ef5a012b3737ca3e16e33f6404b4f13b9cd9bd57f0ac src/acme/providers/mod.rs
|
||||
d1dcb7bdfb7cfdc9c3b88cfb6908201c58532bc888744a13f45853079f214659 src/acme/providers/tests.rs
|
||||
3ec53c7f6e1feb1dcd23bf4ab54cabd8b3601d48977cc01a0ec47c3b2bd88182 src/acme/runtime_bootstrap.rs
|
||||
069b79d455d1126fd3967837493af896a2da9c584ceb582f2ffcceff321795eb src/acme/runtime_env.rs
|
||||
579ddf69314d7f1e11270b00135de64762d77d5ebc25bf98a52945086a4cea72 src/acme/runtime_versions.rs
|
||||
9c1fa211bfd307ce301ea7ef5cdac15269d69d5e01f47bc08a4cfc26502c56ac src/acme/tests.rs
|
||||
1171a1854708210e2f2107445a7c39620b8048478ff0f252f20193be5385cdf9 src/admin/access.rs
|
||||
c51fd51177a476be6462ca980e9bc13f0d0b41538f520118b80a685130f0dbf0 src/acme/runtime_bootstrap.rs
|
||||
5a684eff5f3539c7bb8f66c3b83e7fb62527c52c61da727079d3897e0943f952 src/acme/runtime_env.rs
|
||||
2f02b08d88ad3c1fc9827e5bd3ef463effba633834d9c05e9c0d6d2a0e8869c5 src/acme/runtime_versions.rs
|
||||
cfc13a293c126bb511745859669719a14c72dd7ff6be197bc9e0d0e560deebbd src/acme/tests.rs
|
||||
b28a08ea996befe10949676f40fab5f1036a274c7d0ab1175cf5c43c59849dc3 src/admin/access.rs
|
||||
bcf131abdae425a85b5a54ade51346f623de1e10fa08e18f7c10f1fd2dd0aec1 src/admin/api_token_access.rs
|
||||
5f5b150bb8f51f57462e519650093354ae7b40fcb80c4380fd3391a33f4b30f2 src/admin/api_tokens.rs
|
||||
852820625bd330f6eb87aa734d02ef9f42d1eb5ce31b0f10a8cc06b1287b5bf1 src/admin/certificate_api.rs
|
||||
34e851f725e8605e3c5d9946e56ac035996f3bd9d608169cba3408060d229c9b src/admin/certificate_api.rs
|
||||
a402209141667fdce69698a60dc0b867248effa191494d0a0d93d468d7df9476 src/admin/certificates.rs
|
||||
521ac794501570cfa2e8e50c3a5cec2ca08ee4dbce8ac9c0e0310c09612f1062 src/admin/config_reload.rs
|
||||
159c3970d25fa29acf2483fc9422b003e5d63884713f62baa8375e4a4020730e src/admin/dashboard_presets.rs
|
||||
e9b03088840689636cba66eae0e4e53c495900aae3c2021add6ea3a2ef91977b src/admin/documentation.rs
|
||||
aae1ca0e70d987830bd63948d431f54302083148177c1b551565be12df7fe771 src/admin/documentation.rs
|
||||
d4a249e8c2bf06a12fbd561fcdf5a5211aa5ed0e0dcd5111b84bbb13b3640c49 src/admin/documentation/documents.rs
|
||||
67b901485d5858d5b5bf78a6260035db32241531d99481754c3533fdf404facb src/admin/documentation/tests.rs
|
||||
1ce779b84aa8f47bdb3c34f83593c1f2f06d2235f0319847096cfcd035434168 src/admin/file_log_search.rs
|
||||
ab18acf6fb4ac86fb22635b9219a12dac76d24952c8f15538486267a9b4b7855 src/admin/file_logs.rs
|
||||
b4f225850d3d137ef23569d69774a46ccd5b02b21f7a035133cd14f45179d8ea src/admin/file_logs_io.rs
|
||||
75a51d477283f98d1b0d9b0aba1d593681fe4d120e243d9807c7ab3aa3ec21b5 src/admin/file_logs_query.rs
|
||||
d58a2ed83319176de4e66790ed292447c9497ae031464ec55cfe27174acb639a src/admin/file_logs_io.rs
|
||||
282352eda7957477e7da44f16b90984b26a4a67a8755833bc0a6b34eaf93e3af src/admin/file_logs_query.rs
|
||||
f66ff718f82a326f80808b0a5088bd05a48625be802e5ba305fff3c344b59948 src/admin/logging_api.rs
|
||||
1ba0520c6348246cbb35b60e596e99dc600137c0696de86508cf06587bd86563 src/admin/mod.rs
|
||||
fff31f340853b3f1a26b443e483a0a3937acb1a2cdaff67643933a32a06887ac src/admin/openapi.json
|
||||
74ad6cebcdfdd5ded422c6a720b5ad7d5f9566f1d995efeaec95319e2fe5a452 src/admin/operations.rs
|
||||
d75c1d31c8b57d64b0bf8d925b0b7630411b6a4b3e4be239fd9b8c82b5b97a82 src/admin/panel_assets.rs
|
||||
1a54d9c0594070d24e0faaf9497208085a5c7e0345dd30125e700727be34e010 src/admin/panel_content.rs
|
||||
4cd8f528ef3be20d7b58c928e368afca1c4edc4db22840d2e9effc309aa43bcd src/admin/openapi.json
|
||||
7cfd6593ac9bcea3d1b9e61bbcb7ed98d65ed3190f54f94c1e104541f4fbb4f5 src/admin/operations.rs
|
||||
f14afb6ae141053d83d0dc59df835b20e38a37a9e83f86f0f2053f2bd5d9ce57 src/admin/panel_assets.rs
|
||||
f5127855c2994d052678865df36d703b74f4a0afc633daf7718b10da18d26e37 src/admin/panel_content.rs
|
||||
730c559afaa8a50affc3eb6dc6fbde7005c0356237352fcf8c5423b65725a8fe src/admin/preferences.rs
|
||||
35a7f99c7448c90b8637f4b3a7becca138f1f378fe5dc3f87122151525bb20f9 src/admin/preferences_columns.rs
|
||||
51dbfdf8b228cd4a381aa720b19146418d23763670fca74ff729bd88b13d6782 src/admin/preferences_tests.rs
|
||||
62ecbae5dee00aeeca3eb806e2605372471dfab971cde8f66f11e711df8fcea1 src/admin/public/mod.rs
|
||||
7a00e4ab943f74d2b1bdcbfab7f9cd3f584e9f59536b4aca6c4c31f5f5508d12 src/admin/public/tests.rs
|
||||
e81a0357d88ee3e3f9031755f4b0e2f5d381936abbbe569c5cde4cbc421b64e3 src/admin/refresh_preferences.rs
|
||||
6930b4f4b45257772b321b20a9becdf9bc4610274852948ba38c2d0cdf02dfaf src/admin/refresh_preferences.rs
|
||||
00b5dd3090792986217b28c69bf826748145129e5517b260d95019b1d7b2ebb2 src/admin/router.rs
|
||||
2e7b0871e4af18ed3410f5b79c5fca6c75e6593d71b70b90aa3d80e3770bbb89 src/admin/session.rs
|
||||
e135431cb078ddb483165581123c64af8f00ea67acb3a395ec3e53c85d0d0d45 src/admin/session.rs
|
||||
0c86d94b714cfff26e184541ed3bfcb317c88e45afe084d5f3b28558946dd9b3 src/admin/status.rs
|
||||
2d5b4c28fd0bd48b06890fa8ec44a2296de948c1f88eb2909f4b495710d4e13e src/admin/status_live.rs
|
||||
060e0b378cc48ce17c7e007675467d369ebaf113b64074e595cc471bbfe41800 src/admin/status_system.rs
|
||||
8315c856cd50f1072593ecb30c274d42d82f078b5fb93e7c68a8857cd81b0841 src/admin/status_system.rs
|
||||
cadd7dca29b9aad8c77c7bc23dd249ea37a15adfa4d636a8ef00273a91ce35dc src/admin/tail.rs
|
||||
fd38c6843e09508e90937362719da67a3678c657642ad5147cbce53ef891b011 src/admin/tests.rs
|
||||
666ef444c81e59a2fd47ace3be26e51a8630194d8ffd4db131eb228947fee8ca src/admin/tests.rs
|
||||
c18c369124368f58524652565102817ed69fd25b222b0c5e737ef7632b45dcfb src/admin/web/acl-picker.js
|
||||
48fcd818c522fe80f2c7b2e218f87de6a7772ffd0a24e93502780b03ec78e335 src/admin/web/acme.js
|
||||
86abf50f39862d821cd2e43ca425671aa85289272915132c5a9a5dd1fc4182e2 src/admin/web/api-tokens.js
|
||||
@@ -179,7 +179,7 @@ d997f62e8bd7ac9d4f16bb302800c98ad943afab663bb0b212ea26c35b58de11 src/admin/web/
|
||||
43f4dddd1c3ea7fa42eeb9d7b655a8db48b5ddcc6c68213e08dfc2fcfbe8b17d src/admin/web/app/refresh.js
|
||||
f1a764691f3e2cdb7c6c43e37dae78249561c017a1b74e973a378cb780b72835 src/admin/web/app/runtime.js
|
||||
31201586925e6f4792071d7d03fb05dcc4a69a03c02a4e85eb0746f45af68074 src/admin/web/app/session-resume.js
|
||||
86ac42bd4a6a84bb137d5a3c3dc3d1f4e404a543447845e6ea6e6e8210e268ce src/admin/web/app/settings.js
|
||||
4596247d22cefe250345240942807fbcfebf4e9393457c37d4a97078f255e86c src/admin/web/app/settings.js
|
||||
8386710827e5ccc9432fb46413368f94afc1016425404a6092b460903636837e src/admin/web/app/stream-dashboard.js
|
||||
7f89bfae66e2a08a05a112733864e908f036bb1ee3d8b5b9ff23783b870acd96 src/admin/web/app/web-overview.js
|
||||
849b2ca9d183bdf6cb1e04651cda52da55b8a631e11ab1d827a052c8436bbd76 src/admin/web/cache-panel.js
|
||||
@@ -207,7 +207,7 @@ e6c4d91d1542d0a5b47bb8736f9539d43a6713df5a473b635519d5b7eac2eb9c src/admin/web/
|
||||
0a5fff35555153f59d4346933030a67b6e1a8768cee7a47cfa2fcf1a2c564f63 src/admin/web/favicon.svg
|
||||
7cbdef9192a9dee1f8eac42b85f52b3190f7f6efae50004aa7ad116a910e4036 src/admin/web/file-logs.js
|
||||
b14e7b3578322f309627f6fe965cc16abcf85da3437c9070be6caecae1908743 src/admin/web/host404.js
|
||||
5ca0461ad1a701f5250b60961776c7691628ee532db5183f895fb2322b176c72 src/admin/web/index.html
|
||||
efe0560058dc4addd71f69a9642088f06c245099920b7511caa538adf4684443 src/admin/web/index.html
|
||||
7915a06cebb3dfa2c51833c326586920691ba4431b1f984429b039333f9c2a93 src/admin/web/integrations.js
|
||||
7a12f020fc587205694978ab41b660e9a80487d413fbf6e34fc525eabc58308f src/admin/web/login-keys.json
|
||||
cbd41678eadd994dc5252628ee8ef9551fa9f7d8694ca5abd206240d9a96ad30 src/admin/web/login.html
|
||||
@@ -238,7 +238,7 @@ b2f948bcc3dbd24952c7b1b02d41d06757f49f0c38a78caf51f8f8a687d8480d src/auth/files
|
||||
745226cabb007819370fc6aa680995a03a8a13fa057dacfab0fcc21d0c43bbe4 src/auth/tests.rs
|
||||
32a25e53ac9542424debeaf1b637155bd4e60abd8692df082729d81232eb90b3 src/backup.rs
|
||||
76aa2afe9e7302be39b3512f30d0448d9134300f8ae930d64ada40cf3ad4a8a3 src/backup/archive.rs
|
||||
bb9de9d12dd57289b1941fd05b25f7de1249c3f114d663071b702a05b135879b src/backup/ownership.rs
|
||||
15213c87d4393739328ebf0eacfcb45f864ac12d7bd7509f750a241032f6c7e9 src/backup/ownership.rs
|
||||
37f44cf3ecd71c7e817c76462c4c7de7ca6ecd68c0544f6429a861cdcde1fbdd src/backup/snapshot.rs
|
||||
ece7a5eda4b57bae8f5d819a309cb411b95b1845f5746ac162dee51456365857 src/backup/tests.rs
|
||||
f5afae218f3a6f91bc2f1f5a90094630ce5b7ca574de61807b5a317b13937ec2 src/backup/validation.rs
|
||||
@@ -246,66 +246,67 @@ eec564a7ef886d18ab75289025a47d62bb702f07d63f92d2f83b7afeecebbb15 src/balance.rs
|
||||
8f7975b488fad31f8d83ffedf8a5b6774b86b59290ce0711e779bf2496d5503f src/balance/health.rs
|
||||
344631248c71164187497a10d177d8eaa3e2f4a08111520d2536ec89ae55e1e0 src/balance/lease_runtime.rs
|
||||
ebe2b95f8fc5904850a88207f0690449ced49b28dc14ce5608b706659e338fca src/balance/model.rs
|
||||
aebcdcc1aaf8e38c4f286e6744c09525eef99625d1050479780c0f3c5b429c21 src/balance/pool_core.rs
|
||||
a3d052a928f73ea430480637b867ae874d447e24b1ac913a96a068a4dd74ff63 src/balance/pool_core.rs
|
||||
477132dd381e23f1be197c32ff58a0925f41d3e6aa63fe77c10973cefb2b76f6 src/balance/pool_selection.rs
|
||||
a801a99646441cb748ab05f01101cc9c7a680788eb803c5b786ec6c5a7533e24 src/balance/pool_view.rs
|
||||
05227b05c37af2aebbde1ae37d81c2789088590ca45dcce3ae926c4fcf027bc9 src/balance/tests.rs
|
||||
d789bf40cf9433e2fd16409d112210fe93154588b1ac9bddc9c7f78e1db14426 src/balance/pool_view.rs
|
||||
3e75a3cba5f1cd1af996ab71b6ad50f6aa05ac9cd97ee3cf88fce7c6b7271fbe src/balance/tests.rs
|
||||
16a22aa72f311d1fea6d8da03c3ea1590bc1f248b21876354eecc0da0fd93308 src/basic_auth/mod.rs
|
||||
9a8858b7ff461a4d961ba701ca3ed6eaec15c3f7f05eef8e0e30edc63617605a src/basic_auth/tests.rs
|
||||
fb4bcb9d8852d2aeff41569291fe96d31c719d60789e860629a18cd15b8f24bf src/cache/cache_regression_tests.rs
|
||||
76b7db53f38c95e128fee503381efd3fdcc13340c124ef277faf0fe5c1c25c39 src/cache/cache_regression_tests.rs
|
||||
7def03ace07dc38a4806277d75b6ce673d33ddaaf1c4855fa0a3372be1cf9489 src/cache/cold.rs
|
||||
b75ff512a1c6344483e00d2c67578ceea6b5472c279da0246f3622daa68d7e16 src/cache/cold/cleanup.rs
|
||||
cd5cace53675f995f526e7296822ee5c7fb4b05d01c0ebb641d3efceb04175f4 src/cache/cold/cold_tier_tests.rs
|
||||
79547f697246651c89aac685b26f0701dd3a1db6b028695fa5ecc3d2ae14f643 src/cache/cold/demotion.rs
|
||||
af83946c4df0bb8101bcd3ece96a3193eac625a40a9f087dd2772c82fafdf019 src/cache/cold/cold_tier_tests.rs
|
||||
3c3897980c31a69d96f9295689d1ae19f2190da758c69ee7a0541f4171288bb8 src/cache/cold/demotion.rs
|
||||
e80f84449412c4ae7bc753672a554160519bf1f186b5707252c3286cbe13f02e src/cache/cold/startup.rs
|
||||
83095bc93132f306c537b31ba929669fedac99af3c4f133d0533b5ed7ac4e6ed src/cache/cold/worker.rs
|
||||
c1ce42ca57844c9f80234c1995f1b151dcc9373a0d55387ee887a8098d434f9c src/cache/collapse.rs
|
||||
81d61fad3b5d3d6cc131cb3cbed8438528e7473b23026440ff1b993ee69b5876 src/cache/dashboard.rs
|
||||
5820a33f7be9473b2a67613462e95db029c2e44385e460323936d314963d6b10 src/cache/dashboard_tests.rs
|
||||
7c2549ce80a50f6e998b8f74a5fb86300f7ebfbf8a24b4c35f855bf6a40a7880 src/cache/fill.rs
|
||||
a36a4a255a0fd2c38449bbc462b9c0e21488eae108c70326ab2a0e4c7cee0f97 src/cache/collapse.rs
|
||||
346fdb40d85627b583a01fa17c65e45c822dc7216198cdeadbb3d07904286fa3 src/cache/dashboard.rs
|
||||
4b8bea7aadae500df9a6223fb73a832820c56b47362c298499c3cc995f75f68f src/cache/dashboard_tests.rs
|
||||
4c4c3a70b0e40f9bc806c97939b7d08820e37e5359c87d8f39710b626a869bac src/cache/fill.rs
|
||||
675d18afb53f25c56cba49bbb431fa39ecd9d7bdd192c7b39b0698225de7a2a2 src/cache/invalidation.rs
|
||||
c1357a13658e1ed5158084d3a41ba9ea906512774a5863ce9c56cb508d3fa6c8 src/cache/invalidation/ban.rs
|
||||
d7a02eb7bad37e6a5524600aabb5e60ccf50e26c7a487e2806891c9d8acd48f3 src/cache/invalidation/http_invalidation_tests.rs
|
||||
ba90f7ae78b15c9cd13f9b75bccfb290d99e9cbba2023de73c7198ae24ca5637 src/cache/invalidation/invalidate.rs
|
||||
bfe59157d1656cdaf8e7cd82e659b25c7fcfd21c9b7ad17f7390466d7393957d src/cache/lifecycle.rs
|
||||
bbd9f372648d89b5e14d5b58029582d37f66a89752caf2c14eb1cbf8f24bb7a0 src/cache/invalidation/http_invalidation_tests.rs
|
||||
6223eaea3f061b111330cc26b28d85b9b239bef30328025f2ef337291e22a445 src/cache/invalidation/invalidate.rs
|
||||
9bae8be41d1e6b30cda51feff99fd77738940fa975bdd4ece7da75d936f07b47 src/cache/lifecycle.rs
|
||||
bd831807ca4720b3a41a6ea1d9a6c0ed2d935225e2dacbd9313be064f2e4a20e src/cache/lookup.rs
|
||||
d5d01ffcc68e5ec6a913f20df108964a5b325f1aa972c078ba5e6defde81591d src/cache/lookup/hot.rs
|
||||
a0a23e7ec1baa403524811f8096bbc026b1027b7b1b79357ad920b0a4be770b7 src/cache/lookup/hot_hit_034_tests.rs
|
||||
9cfb83f414bdf4ccbedc3daf2eeeea4cb2ef83ab7c6aaef6063a331c9fbf5608 src/cache/lookup/hot.rs
|
||||
4148106b9baf70e41eeba24233b1edbe8dd6f927c11f2c7647e89fbbfb60555e src/cache/lookup/hot_hit_034_tests.rs
|
||||
e9c6ab0c2be9f96573f826e6a1b9e4c2b8b526f779e72e95a6463ae07e45ab55 src/cache/lookup/insert.rs
|
||||
0338e0066e134b9e8032f117d9557b9bc5edc574f11710c2d36a6ca1c7467a99 src/cache/lookup/tiered.rs
|
||||
5303b3031d3ad97d7c4e75e5667d16775672ac1aeaca91c00f79f76ecb286cbe src/cache/lookup/tiered.rs
|
||||
639d5be6258699ec7e9f260ec33bd2c366203b6655bf0e98f30517c2e12ceeeb src/cache/mod.rs
|
||||
0c8b0d550e94d4474dcdf991aa0340228dc5f2f904f39350e6e666a16f16fe87 src/cache/model.rs
|
||||
952ce10a89c714571a5b8a79d5fb3ca60f5216901f95b3f82e7e257b4682fa9d src/cache/model/cache.rs
|
||||
c409174a9aaf20c69dc7b329108d1c26b5672a7341236cf639480df48800d262 src/cache/model/cache.rs
|
||||
0ec4f6d0adea1ed80a3ca17c68c9c85502491da2904d9d690b4169ab9b025b21 src/cache/model/cold_metadata.rs
|
||||
4a44e2161c2e8b2d6decca6caf1f9315a723c888e0894236c88c656b01b8442d src/cache/model/entry.rs
|
||||
eee9e6614cc5a185e07686f9ad24525728cc49dfe8b9ce6a6bad0c14f3f0bcd3 src/cache/model/http_invalidation.rs
|
||||
a7b4b861127fe2b1527f12e5ce01ebacf60fe266f913467a2cc66d7f80e98c60 src/cache/model/maintenance.rs
|
||||
298fa122c7583bf8447d08255c4d0ab335e23c7e48cac3f621f235c201046fb7 src/cache/model/settings.rs
|
||||
000d82a19cda1501f12a8ef539c1e807529e104a77181fe541738fe6b22908c4 src/cache/model/entry.rs
|
||||
ff1c3a1a3bc0d26218dcc943ef951c2a212c180bbf6e4bf1c542ffbf12a9f150 src/cache/model/http_invalidation.rs
|
||||
dc1153685671be70c28bef814d72d8ef09afe070598f528ea62260c54d43b26f src/cache/model/maintenance.rs
|
||||
e9a17446038508275e72a85bf2a4fdc03aae1f8da98433f57de902a8aa22171b src/cache/model/settings.rs
|
||||
c2efe75f740ba31e83c49bf76e7fc179e897f41c140eea700e2675ae648e4a1c src/cache/model/views.rs
|
||||
e26dce02df9c043329ca164fed215d271781bce8fb03240f528331bf3df6b9d7 src/cache/policy.rs
|
||||
d01b8443c6d02a9b5d7f1477719865ea105126b8620e8fe13d7b4711e47fffb1 src/cache/policy/request.rs
|
||||
7cf0318d2b6dfc5f00806d608d78eeae9535b4fbb22b28826aad11b72579f9f0 src/cache/policy/response.rs
|
||||
b6dd187fe9a6f540653c9b7a0bac4e789f1c606b58bf99691e027bce776322ea src/cache/policy/request.rs
|
||||
130ebd918dace9552eee4f9633b8ad3fe5a1b7945bb00ae6f6683017cf10f527 src/cache/policy/response.rs
|
||||
e59efd322f518ebd7b5b154115188f382c2cf7882ca0a401736ba5d685981ea5 src/cache/policy/scope_tests.rs
|
||||
982d4b32f5ef2f80e6e18dd7334152a903631d73edd2db532915e272b6bd2f59 src/cache/range.rs
|
||||
48c260e8dd75c89fb4518f6a20ece21017f69b0f5c9f9d80222ae34fab62b3b3 src/cache/stats.rs
|
||||
42a6bd984ee8ab69ba03030a113818252b26d5b922262b7759367d67899353e0 src/cache/tests.rs
|
||||
276a557d0ad85c4d5a7a3dae1e49e748591c79879f4c0d5784ec277ce8d08023 src/cache/tickets.rs
|
||||
9547a2fc3cf5220aa3edf3283e09b091f8b0fb6ccbe36e53f84c625c7482e08e src/cache/v022_cache_tests.rs
|
||||
c2d8548d12aeb2aaf02d47f6162904170526c9592aad9839a6bd5490feb269bc src/compression/mod.rs
|
||||
2b556ac9179b8a92de368f5e907e4114c2fc21a89155fe2a05665c45c08b3883 src/cache/range.rs
|
||||
e1d3f0512d6290b0ac4998f47398a0a7c404db249c5bbdbc4ad4767071013a72 src/cache/stats.rs
|
||||
8a300f5dad44815401eb23f4f5a157893761852ba4f3005041e0eb3f16892ce3 src/cache/tests.rs
|
||||
d0f7a9726c0a06553c91ca4d29eca207e9a9c3201fab371bec9dc5f6457ba12e src/cache/tickets.rs
|
||||
b7c063ed4c8ca96714e1dc5d279f38fc521da2132faad7bd4f40311352a71e7c src/cache/v022_cache_tests.rs
|
||||
6e503de08f3ea67608e534f5ceff58173eb2351d2fa7777e8fb646ed1c5bb7ce src/cache/varnish_compatible_tests.rs
|
||||
5a8022f6f4721f9fabdc715e01127d9299d47ee9981a79d26df1981448487d20 src/compression/mod.rs
|
||||
2bb1ea392dc18553a03a6ae1c53f52712ae86571ea31b1bcd93c8fdec2cb60ec src/compression/tests.rs
|
||||
e695079333ebdc2a6e7b3337cfabef171b3a0a01da0597b77feff70d417f833e src/config.rs
|
||||
9f6272bd6d1f403cf6324b12472fd5c7d911a387139b57105ba1819e48ea0a54 src/config/backend.rs
|
||||
7261770b504b5d2bb4637a2a755c8ddd8301636aaf703ce9c8a01b0623bf339b src/config/compile.rs
|
||||
4febd62f15f33079b843f59fed94ffb1e9cc8693f58e54f4ab15ee03fd653b9f src/config/internal_routing.rs
|
||||
f9a400d66f37056a0a2d8c77fb44c2b3db9fceba3511e4a5b1e4b98890d27b13 src/config/compile.rs
|
||||
fbea01fea1213d98aea812c1b78d5db289e09200b98ae514d742235cd3fa70e1 src/config/internal_routing.rs
|
||||
0d9f62fe4600b230e200f41652effc22ac7c1b649fbe63505ed6ea34c644feea src/config/model.rs
|
||||
5a2b888c2b2b3e506a8f1ee846ebdef60c1b3a3befe312d05431d4591a78c709 src/config/route_policy_tests.rs
|
||||
75839458ddbc7480ec4492a95eeb67b617ba7d62f7b67e7a767a3453b74dbcbc src/config/route_policy_tests.rs
|
||||
40e9483d7b2450f55d29b46c408727f4e331b85ecda44fbd7b96bd9a09f02655 src/config/routing.rs
|
||||
422c43ef9fbbf6b9b8a44c162a95cda890ead6dfa1ccd24da4782844cbcb8834 src/config/snapshot.rs
|
||||
e09a3a8ca70ce7e42007553d48798bcb8b4fbdf791e338b36f238d7ab99fd05e src/config/tests.rs
|
||||
596a6697e8eea1d78fc86baaf8e9eb906ac38db6c1fe9a7ac62ecac85875940d src/config/transport_tests.rs
|
||||
dd9a6ad8f58e0cdd1ae74f3f972fee0ac14383cd8b8f518403b9a36c169f35bd src/config/snapshot.rs
|
||||
b7b0f851b4ca459fe8844a2e4f9cdcfc1135dec4c06f99beeea008c5b35c2ba5 src/config/tests.rs
|
||||
f35de0ee1516ece6bbfd2b2a7db7d1e0f5048b0ec47cf2a3765dffb799abfd93 src/config/transport_tests.rs
|
||||
eb04a8922da26e45c9b6005c0cdf1b1ddf2da3c3b680650b22a1d1f16d17a4b2 src/db.rs
|
||||
e37168285f1c7e17a17a028a151784743e2ed6b9b5daa5560eacd6c0403eefb6 src/db/api_tokens.rs
|
||||
111baffc0fc7d2001d6b7d2542f95593ba5723bf37af7b209a273bc56545436c src/db/certificate_api.rs
|
||||
c290d0cb02dfa5d2c60ecabac1cfb20c8884e3d14cca1944906c6d8e677f1784 src/db/api_tokens.rs
|
||||
892ec0e5985700cca399c861197f6c9d2f1c823d8d95b88abac9d27ae15a069a src/db/certificate_api.rs
|
||||
5491dd7bb9b3fceac97c4dea63aba6d5c7abcb0fbd06e36ae986e00c79bc07d0 src/db/dashboard_presets.rs
|
||||
2ff744223934685439374572b83fd639bb3eabdbac168bea4a6501a6e9ce0ee0 src/db/history.rs
|
||||
c05a02618d476e4670b4f9930555f199cac776cdf09edb8fcc1a675695b8f99f src/db/tests.rs
|
||||
@@ -313,9 +314,9 @@ dada314e1709e960eb2e225b4d10c3cd12606c62c4bc2c0220aec1ba133e4ade src/demo.rs
|
||||
5808205f03401e3f2c7f5c826d5de76e83e4b6f94c64ad3e50f505f985f6d26e src/diagnostics.rs
|
||||
045593a42a6e4f632e5052c655788f0843faa313fc929265b89509f6dfff91ed src/docker.rs
|
||||
93a8a3f6ba12761ddcbd19f22f32fb2c0e6948b660fb774ddd7ebdba9b6562a5 src/docker/client.rs
|
||||
da83e954040b281e99a9cacdf750d1745333b6c8ea1a5c3b6793ff01168e49e4 src/docker/model.rs
|
||||
a5239889203ac3fd6c82824ec3a8dfb1f250648ab05e3dea02a09183f82c1db2 src/docker/reconcile.rs
|
||||
3c0d97c9f6b8a5ccdf779ac2a965c39b9bd899dbb28a84e128d81fa75ccf696c src/docker/tests.rs
|
||||
f69087a82cf353e9a92fc97ee96510dbe0382efa1c5e53821d16c455a3eb95a4 src/docker/model.rs
|
||||
f095e5e3c564df409874019c647f7cec2156bf5a845b5b84864879fd07cf80ce src/docker/reconcile.rs
|
||||
2e8d4841665cc1d29e6262a1789bb64ced1cecd0036681cc1ef7b5d5bfe22065 src/docker/tests.rs
|
||||
e36db1ed3188ffe54df7fc4ef76c4b453f23683bb7b8cdf601046e2bd50e0403 src/forwarding.rs
|
||||
08d2e08a798abb944a53570f0bdaa08f1266b1107677ceda070091af4c2fc121 src/forwarding/peer_formatting.rs
|
||||
b821e2efd2939cb13d01e402532f33feba6682acb6a7a3223be086c1cd171820 src/forwarding/tests.rs
|
||||
@@ -329,34 +330,34 @@ c1b49bef28d87712e4c46138e70b52c4bcfb1a00196579031fac043d0b4aaa7b src/geoip/upda
|
||||
61a2b01db9010f9debfb38b43a26bf588438a5e470dff938e4e54f9d7ba46732 src/headers/mod.rs
|
||||
e4f07bfb7eb75b6897ef812870caff158679a3046d64582428abe8c6df490dbe src/headers/tests.rs
|
||||
d7c764af29c132e3d8d1fae1bdbe6bf20a27046dc294f83761fea335726f2306 src/http3.rs
|
||||
4b56bddbfaa1db9151807c7bc016e573e78afce2ecf593df628e2e311df61658 src/http3/body.rs
|
||||
dd4e4200743b43895c0ee2071dc9ce36659b10251ce23d1082be169594a20d76 src/http3/diagnostics.rs
|
||||
0cc484bf0cc59a55a13e0e70435833a9a7a22ad7dfb5b9f86e059cf70a80cc2d src/http3/body.rs
|
||||
741972222414c280104acbcd8f8071bed9cbfcfa2f503c487c11c56f553f53cd src/http3/diagnostics.rs
|
||||
49ce4452ef7973cafa2e4071e2e14be0e16000e931a6501e4dc613652e49e230 src/http3/identity.rs
|
||||
0b41072f6bcf28725c80f471584cd55d4900424ce5d55ac7f6909813788c63fd src/http3/settings.rs
|
||||
01ed8610a8d169bafecf5ef91d325042d9b59a228caa8a89f76005cee20e6811 src/http3/tests.rs
|
||||
5c550075c7b0fe687ad02095c1cad57b46b579fe21dc5371525b6c77db459886 src/http3/tests.rs
|
||||
68fb5ab6a889995a66ad12cb6acf88c5d04f0aca572e2ae15f1a9cd171a5f24b src/lib.rs
|
||||
e8399753a6ff49b7de19edb0a268bf871c9979a518354160cf07b4669051fcbb src/logging.rs
|
||||
4310aa77bec91dc473808787cebef664d2c9bda8d78742ad0fd410670f0f4f56 src/logging/error_runtime.rs
|
||||
9f9705e07cba9f3c2888babb2eef63b706549042e0f4ce29fb6a1646ae58f9b8 src/logging/format.rs
|
||||
e4be3ad758c3d93ce52dd3b1ab1a87810e5226339400ed997607a5b746354751 src/logging/error_runtime.rs
|
||||
b2ed730006fdc080cf7eafc6d20bb89661c639631c89642d110e0c1319e431b5 src/logging/format.rs
|
||||
e51524d45ddf54574bd33d71dd4ab18abbb642390fb6b6dda2a2c6e5439fe9a2 src/logging/model.rs
|
||||
3afbf5083695f21ae4a8bff10b81ec3dec55124007c31b8a0d36c3014e4873a0 src/logging/runtime.rs
|
||||
48187ebfebeaf6863207ce338df2d6d0f418fc3aa0689481c23c2a8ad9970b52 src/logging/tests.rs
|
||||
bf898b318feb9bd3dd2c335b6b1bad172da63fd5cefbff3e267421ce37c076fb src/logging/runtime.rs
|
||||
a9e453c94fc37e37d9f1f461494fffd5f88e13e15f6cd4158464dee4fafb14bd src/logging/tests.rs
|
||||
0e9993aa6679381d91f3a22068b30e1611439d7fe50900f49a4a73ffdfbdb3b1 src/main.rs
|
||||
04ad738f90c67754f9f133863a0e2ae94665357f527c2fc3db05863087ae4d83 src/main/admin_runtime.rs
|
||||
2c32c9b2014f9fcb111b64dd85f2106a8731b6d57fc3721522b2ec5f4349f4fd src/main/bootstrap.rs
|
||||
87e69b46c548b861e9d90d9d2e42dfc2630891f4583800b1942f9065d25e29cd src/main/admin_runtime.rs
|
||||
224da3127b5f846a8932fb7f4b6e23d0dd590dc0170506267381d66042c64666 src/main/bootstrap.rs
|
||||
5a98d0e249338e73aa57ae2e352dc16db2f79c2d042c1544ce1c2022da76a31c src/main/proxy_runtime.rs
|
||||
b240033715323e7cb7b9bcaf92edd481f7089b4da6bab25005ca6733da8756dc src/main/shutdown/mod.rs
|
||||
0a6578a0f4023b9f8d73043bf942dc5e096ef9afb8c0d2f131c14f65d08ac01d src/main/shutdown/tests.rs
|
||||
ca01c97cc52a50797306193a546e4379fe3ce9401b0c936c756b881180315ab0 src/main/tasks.rs
|
||||
a719c51aebcba0f16f8810c37618201954e79d6806da085ee6c5e4697a05b521 src/metrics.rs
|
||||
9c7ed78345abc33d260f8d5cd52339bf8de748c08b53eaa2bdea8a32a0ea2a20 src/metrics/global.rs
|
||||
def9a23ea4edd87fe142ac597387f1c0235088c95c693809f5793279d4cbe02f src/metrics/rate_sampling.rs
|
||||
31154052757c2bb975b8ce8cad67f3fad7b5132b615a73d5b0d7bf1b5311722b src/metrics/rate_sampling.rs
|
||||
f27f1f8bed769883d1a7ae6a48f89f7712394dfab65d05702b0f944f0a45bd8e src/metrics/vhost/mod.rs
|
||||
40cc25ed1993127dece24857221b6da2debac37faf403abcb451ec442a240273 src/metrics/vhost/tests.rs
|
||||
e7ddf1f453a3e207ece18a4358cb44cc02ee68333ecc0b6c68028ad17661cc8b src/not_found/mod.rs
|
||||
c915d30bbd7032d867e7916b4cd45f3bb7e7604d3f4558f4383c59394b4300c6 src/not_found/tests.rs
|
||||
ee401f943bd8b2706c33419ed69102269c08dcb4ceba6f4be2ac0861115874a7 src/metrics/vhost/tests.rs
|
||||
9c96c3e4edb20dd0c36b5c373f1925dd60368e75853002206523072d418d5417 src/not_found/mod.rs
|
||||
fa2fc6c6987a8356a9da92cade10db62426d8863e9cef3c0d4324c45780c5b33 src/not_found/tests.rs
|
||||
d32d757ace8753eccb842c24b7af77061141478d10fe0acdfb05263d19e9a64c src/pages/mod.rs
|
||||
8416712d3e8ce81a1794152ef98220313066527d613142cc0958c4915add8c39 src/pages/tests.rs
|
||||
9d3f4db663016033c4ba0d86e30367bd5a1ab79c8bc121265d410698104fa19c src/pages/tests.rs
|
||||
5650a3f70162abd97021e0a51a92cac2c4dd39004426ef99dff36cbb0741aeac src/prometheus.rs
|
||||
192a780d5874afc158d62a7dbe1687d734635afe9342fff526b8a2f6db4e5633 src/prometheus/core.rs
|
||||
2321ee667569803dfe6c92c0e98adba0ac8fcdc6a3eacd5857233f1acae93daf src/prometheus/docker_misc.rs
|
||||
@@ -366,27 +367,27 @@ f9aab3297fcf647295849f77cbf99197f4dd27efd6817e54c03451e04972430c src/prometheus
|
||||
028e1dd9f2ec2afaf699a6b21c2d4b0d96e76f11f5e4ed009c233dadf0f3be51 src/prometheus/traffic.rs
|
||||
e03f0d6b3f35dae6b98c394837aa0d17e4d73a8306767b4c607868bc00c30286 src/prometheus/vhosts_backends.rs
|
||||
f1b0254f53b1a4336bd8170ad441ba072b49a114e497b985cb20699b4e375044 src/prometheus/web_php.rs
|
||||
0e8db3facf4f4df7b05f058e2dccc8521d88bea9da67ac0889b77d349d524d9c src/proxy/body/mod.rs
|
||||
569eda61453affd053fbe24fa59652289cb12d22b77e64caa38325bbea48f7df src/proxy/body/mod.rs
|
||||
57a71c9c6e4e0deba5d05963b9870af8f4c4d8dbd321ed4e52cee88746c997f0 src/proxy/body/tests.rs
|
||||
dff5d29ad6d126fde26f2b5e770c3b35275a82b6d59e41dd85edf28ac5eb2740 src/proxy/cache_helpers.rs
|
||||
7e3837d2f6ba7d07ca2cbabda57b315f5a7f4d75a13e5eddf6861a150d0d2ed6 src/proxy/cache_http_invalidation.rs
|
||||
d134b0eb617f82f9971b3f3461379ea37c57bd0079bf54748d0c434b2ef1b475 src/proxy/cache_http_invalidation_tests.rs
|
||||
a679baaa062beadff9ddb61a3bd6cde1ce27cc62147d2e27b468c0a8cd32ceee src/proxy/cache_plan/mod.rs
|
||||
a03b1735daa8fa8e40cf5bd9c6e200d211baf19c30f62522d4237ed56642bce7 src/proxy/cache_plan/mod.rs
|
||||
3404b03096862de1050088f62cdd811ea1ab61d191f902501173107f81f23b9b src/proxy/cache_plan/tests.rs
|
||||
a0b9e2e9ab0bc89c7b64bd19365198234b1c5c13f455ea47be122a5660639b17 src/proxy/error_fallback.rs
|
||||
c825f436ce0730ce542f51a1363a0fdfb0b1a4113a2257384d052de1afd56359 src/proxy/forward/cache_fast_path_tests.rs
|
||||
fee36419c7e308cedff3b73ed1e8c5fab1fa054aaa6e0ccc016dd0b043c32c42 src/proxy/forward/cache_fast_path_tests.rs
|
||||
a20cd11a504e423e5b1af5cebb5b4186530d4eaacaa02c3212a1174cdbfb6498 src/proxy/forward/cache_lookup.rs
|
||||
0f2eacadf1447db8aa1c1a78005aa262e0f747096bfe7e0a0e41a2cd31a0d17f src/proxy/forward/h3_navigation_tests.rs
|
||||
287012c81144d8f15af4a148ce3ca911d431bc59adff44e697567561aa372bb3 src/proxy/forward/h3_navigation_tests.rs
|
||||
ce97cfcb07d90415937f0520ee7175502b22e60694c1ea8e3d2b47678d190e5f src/proxy/forward/response.rs
|
||||
02e1fbe16e59c746d57dfbabf655a729a2cde8131886689532a414c47467a53f src/proxy/forward/route_cache.rs
|
||||
f3c3b8c979c06bd84a72969f2908be1052097e32f3a21f0494dbd3ce72f17796 src/proxy/forward/route_cache.rs
|
||||
3f91a40a01378d1fbac56ec376df6626e0c4fb6c3b8c8d42583b9c398d368ad9 src/proxy/forward/success_finish.rs
|
||||
e631c63fc10a23e4533bbd158659710b184656b323d0e6169a8627294c6972ba src/proxy/forward/success_prepare.rs
|
||||
aa30766a5d584c2143488f16caef19c1d369a2c7c00b5ff960eaf2ccf4045c31 src/proxy/forward/success_prepare.rs
|
||||
e9ac9be64f6f83c4ca2cd5d299649f24dd16197712083c6dc10e55c662c65b80 src/proxy/forward/upstream.rs
|
||||
53ae013330edab4d97a9cdab2c513f8548f6816aac60f7035bf3433a6a2db818 src/proxy/forward/web_source.rs
|
||||
de548bd191c57b76b595f0a932195d303b43355982080a185c44f1973d00702c src/proxy/forward/web_source.rs
|
||||
3340583d395fcc859cf3421f4e33cf8347915ee4c468f7d0e4abebce8156fdca src/proxy/forward_entry.rs
|
||||
9b25f5e3ea4443a63ee6f45d12e1957dd316fe8e85325fc00ea416faaab1025a src/proxy/h2_graceful.rs
|
||||
5b07b98d855453d5a4272f5fc98a75973c3e6032416e0fe4f7f151c1bf239fd8 src/proxy/headers/authority_tests.rs
|
||||
3e642599bb0aaa3ab36d83a69d9e04541cddde90f38661934ee0255011ceefb5 src/proxy/headers/mod.rs
|
||||
66efc52d64d34667ba7419f8a2da89d2efb1af1f426684f4fff8caccfdf19996 src/proxy/headers/mod.rs
|
||||
0f9314d1380febe436def36b5f381731e97cbac90625637575f38f3d72eaaace src/proxy/headers/tests.rs
|
||||
c04451ac8abebf4662ccc3ee4610d5342ad5382da2098f7af5db274d079770b6 src/proxy/identity.rs
|
||||
a08ee061e146cb7a08311106f73a04468c89f77b6ad05a2c623621a2ae9faf2a src/proxy/mod.rs
|
||||
@@ -404,7 +405,7 @@ faedf6cc2bd4c42f342a0aa188b634d6b8d280ca0e121032977eadaecb88e9d7 src/proxy/webs
|
||||
7e9c4d4c207badabf90630223964bb2ad641f06d4149843cab751f192b8b4adf src/proxy/websocket/tests.rs
|
||||
a44421714aab37f7ceda19e3ec2512c645d2a3ce5dcb3da5bc7a0d87a442d6a8 src/proxy/websocket/tunnel.rs
|
||||
999cbf85cb6e917db529e30ba4a5eed1cc9e95a054da7b3039c730bb80061449 src/proxy/websocket/validation.rs
|
||||
00aff5b5b0719930230eff4d7e3adbe998cf0258bf7361d0913679c863afd3fa src/rate_limit/mod.rs
|
||||
80d0f744f7ad9f0d1edeb0d5c23b13cb40431f6b6f4d10d534ed34d4198e3dfd src/rate_limit/mod.rs
|
||||
2fcfa9706eb0708519d5181debaf3c85a86e401a8898df72f9eaf0ab72c9df85 src/rate_limit/tests.rs
|
||||
e53c40b85792d4804a432e3c97dc13af8e29304bb0d250ee9ab9018bde522eeb src/redirect/mod.rs
|
||||
811c83ae9fd0f5a13d35b5443cd37843f82b9d600bee4bb136ba9b87732a5347 src/redirect/tests.rs
|
||||
@@ -447,11 +448,11 @@ df98becda799b6bf4ff5e2fec7d0e0a486e6b7eca6f9f5ad49ffdafd49a4f498 src/tls.rs
|
||||
2af2164ecdf2b7fd9eef7c6e358dec053dfac9aedaa501dbb75df742d18638b2 src/tls/acme_tests.rs
|
||||
7425ee6c839f85d792e9251c6b9039e72fb49a5820a2266f751e6f4967a5871c src/tls/certificates.rs
|
||||
2ff3c219f87bd82677045a4809d3d94921c5b230bbc2f3e7131b07548f73ea7e src/tls/external_paths.rs
|
||||
60c16793b3d6115596e79e2cfe5436ad774709d20ca1cd55883e0f44e40ec871 src/tls/external_paths_tests.rs
|
||||
f88a6c8c2e35c3aa58b7763c71a5a2cec82a34f24478a98b0960b81659a1ec4c src/tls/external_paths_tests.rs
|
||||
7b4c0f58b3a1e1791bb3c682a001b78bfdbbdafdbc143db8063b3f22dc168616 src/tls/server_config.rs
|
||||
9d6f048e791a3b7152904d1728258d298ad9d34aa3f83d13baf1b09a6fb7601d src/tls/tests.rs
|
||||
d9d79edf5a8ef6e3b39a21d35dd5ec6e5a336047117918949e7ec6f5b20ed3f1 src/tls/types.rs
|
||||
d637a77a9271736993f2e49022f752750364d4c6ba3cfd5cf7c9c3c8f37154b3 src/traffic/mod.rs
|
||||
a535c8526b38de2990da7781e158b9ea70ef8c1f6fae0aac5ce6e9da21d3a309 src/traffic/mod.rs
|
||||
dc8a83fae47da0d86e6ce0a329cb5274233264df56eebdb56b9bf37cb7be2bb4 src/traffic/tests.rs
|
||||
65fcac840f8b5f1508213e3f374aa318b450b0f9f90ba827c5ea935b9c60bee7 src/transform/apply.rs
|
||||
34a06c2dc635e80690961ef61fe84110f9578f55adf89f92a04668783ccb0a98 src/transform/compile.rs
|
||||
@@ -467,14 +468,14 @@ d13fa462d6df516a4cfaee9f4e184044c5b6345e311aeb3d9058efafe54e4c5e src/transform/
|
||||
4b52257e1a3643910b5e7043852d7218230c0021c31215d90d0f8e384f2ae233 src/transform/svg/mod.rs
|
||||
0f53c64f442390ee20a59087a10f8f9ffb58053263e9aa848ddabfae1a6f3f51 src/transform/svg/tests.rs
|
||||
d1f3f53fedae0d8ef69eeee457f7d30ed5a670a1ed4ced60683400ee46680260 src/transform/tests.rs
|
||||
64f711d2a0063036e3a2cba470b44eb165f3574bc28cf273296c2c3adb9ed4a5 src/update_check/mod.rs
|
||||
8d38f2f7d4ca4dd453cd0e2337614ec704fbd0a36d3e2374cda43f05dfcad663 src/update_check/mod.rs
|
||||
c42d000d1d576721af3ffe930589388693001b8113554a7658f6dcbc665b5d1b src/update_check/tests.rs
|
||||
b7ee3629a8fde0972bc1822b764f5fa2c813a760dd5dfb7f1ce643a7db8f9f75 src/upstream.rs
|
||||
fe9d4deb34cea2408ac5a1030315989f29a6a7d078a46ac1b59d12aa07f67878 src/upstream/client.rs
|
||||
eb513923f8951c8bf30bad3cbac77d34f5ebbc7af3ba69a08a25bae834f8a016 src/upstream/client_tests.rs
|
||||
8c88d928b823e4b6ba6d852f74664c770d8b3fce32bc76c583dc1f672fe33f14 src/upstream/protocol_tests.rs
|
||||
ae880b40197454ea3fbf4d2113984dc372098b2e54b97e87c83cc319de253377 src/upstream/tests.rs
|
||||
b88cb47a009be4924bcf069b05c3e788d1eaf2b15cbdcf3099036ece89cd0d66 src/user_agent/mod.rs
|
||||
e68599c376d190ae7bdeb154cb3e5a7151feabeb0d688360327dff06574d985d src/user_agent/mod.rs
|
||||
6d7cb73de7d8c6f3780736480f5f81ef08813f4626fd5ed494aca0552cf214a1 src/user_agent/tests.rs
|
||||
d61c427c1e9cf457f1232b822d73e846e9f329cfbe61215e7ca061d53762155d src/vhost.rs
|
||||
54b0c1d2f04e5c654123c3422645eb5a0a9609141cc4a1c6addca2d028392772 src/vhost/error_fallback.rs
|
||||
@@ -507,18 +508,7 @@ f826d8816bdb9edab966e10991e45335625ef7d7376169cf6fd1e0e5d01bf868 src/web_server
|
||||
400e1c8aa2fe857d96036a64499fbc3de44c1e3a53811c5b25101fb843359792 src/web_server/security.rs
|
||||
b791762b4ab7a43c3be19df84e523faf3dfb4df055f66d02178f93edb60d2204 src/web_server/serve.rs
|
||||
df888adf893d0b6b99348d19fa07bd9c2b8fc0ce7f411d06be7411afb4311fe0 src/web_server/tests.rs
|
||||
cf729dc5d00132736521887e77ab0ab5280ede6840e1fb225736ccab09748f22 tests/acl_picker_corner_styles.cjs
|
||||
2467a6c2295d3fb2ad84cdb4a85176372953034fef2f4d95dc3bf58f019efe21 tests/acl_picker_dom.cjs
|
||||
8bfee0027ce317f3427ecdf9193549d4a52db58a7b2b99db7cdeebc458d7d4c0 tests/cache_outcomes.cjs
|
||||
667352945e67032a26e9f246a3f89b20b431b2cab8f48bb77b11533d89b3f2a7 tests/css_usage_audit.cjs
|
||||
2e957134ae1b041ab1f1cac6149892a2704bd61a37fbe4afc0810e2911b5cedd tests/docker_vhost_actions.cjs
|
||||
c1b806e756a84913d0a1cd2ace0b0f94fb5f5817e0480870a65279b4d7fc5bbb tests/docker_vhost_metrics.cjs
|
||||
f00743af2cf4a5952caef7a1dcf68e7817b5599a252a9973e1c22045517c0b0e tests/fixtures/argon2id.json
|
||||
930cc63183479400d01195574ec0246a482618915bc3c24b4d48a11faa286018 tests/modal_frontend_0346.cjs
|
||||
071d590439bba50b526e1b2344b5ee414210af8f4f6a318d1611640386de576f tests/ux_0345.cjs
|
||||
b312f9f5d5f4b3d30f935ab3f3c893fd8b8f2d571acc8198a1a89ed9ecd1f0ac tests/ux_0345_followup.cjs
|
||||
67353441435c6378780e4b6c5dd8732d7160f7fbce8df9cf4791cbd6037f5840 tests/vhost_content_type_ui.cjs
|
||||
3421dc1baeb2a9882907b09e816213b375767089c79fce710248c61b9c3e1ae2 tests/vhost_ui_layout.cjs
|
||||
eca68a07c2b1e45fdb8f512294f5a432db3ae5a6aec8fb200b47f155cd9a31d6 tools/README.md
|
||||
358c1e94dd2b4a756430e5335747f0b437345b1713670a9972c5bcf78b837ccb tools/audit/admin_audit.py
|
||||
7c30c280d0b0a8bf855eeffab583ca34dc161255f7ef6124148aa979c17c26d3 tools/dev/memory_load.py
|
||||
|
||||
+32
-2
@@ -8,7 +8,37 @@ RustProxy provides an optional shared HTTP response cache with a bounded in-memo
|
||||
2. On the appropriate Vhost, enable cache for public, repeatable responses. Restrict or disable it for login, personalized pages, uploads, APIs and responses carrying secrets.
|
||||
3. Ensure the origin supplies a valid public freshness policy, or configure a safe default TTL where supported. `Cache-Control: private` and `no-store` must prevent shared storage.
|
||||
4. Optionally enable HIT-only diagnostics. Send repeated identical requests using `curl`, then inspect **Cache → Domains / Stored objects** for `MISS → HIT`.
|
||||
5. Check TTL, revalidation and invalidation after updating the origin's content or configuration.
|
||||
5. Review **Varnish-compatible cache policy**, enabled by default, then check TTL, revalidation and invalidation after updating the origin's content or configuration.
|
||||
|
||||
## Varnish-compatible cache policy (0.34.7)
|
||||
|
||||
**Settings → Cache → Varnish-compatible cache policy** (`cache.varnish_compatible`, **on by default**) changes *request-side* cache lookup, not authentication or the cache key. Disabling it restores the earlier strict policy without a service restart. **Changing this policy invalidates cached representations** to avoid mixing storage semantics across modes; allow time for HOT/COLD to refill. Effective settings also apply to eligible embedded Web Server resources and HOT/COLD entries. Existing JSON configs with no new field inherit `true`.
|
||||
|
||||
| Condition | Enabled: Varnish-style | Disabled: legacy strict |
|
||||
|---|---|---|
|
||||
| Client `Cache-Control: no-cache`, `no-store`, `max-age=0`, `min-fresh`, `max-stale` | Ignore client cache directives for lookup and freshness; a **fresh** object stays HIT and keeps `Age` and hit count | Revalidate/bypass or constrain freshness as instructed by the client |
|
||||
| Client `Pragma: no-cache`, `only-if-cached` | Ignore both; do not force backend or a synthetic 504 purely because of these directives | Revalidate or give 504 for a missing only-if-cached representation |
|
||||
| Origin `Cache-Control: no-cache` | Do not store, like Varnish's built-in VCL | Store only with a validator and require revalidation per request |
|
||||
| Origin `Surrogate-Control: no-store` | Do not store | Existing RustProxy behavior |
|
||||
| Origin zero/nonpositive *remaining* TTL | Do not store | May retain a zero-TTL representation for revalidation; never a fresh HIT |
|
||||
| Expired but eligible object | Allow up to 10 seconds of background-refresh grace (or explicit larger `stale-while-revalidate`), unless `must-revalidate` / `proxy-revalidate` forbids stale delivery | Only explicitly configured stale/grace conditions |
|
||||
| Origin `private`, `no-store`, `Set-Cookie`, `Vary: *`; client Authorization | Existing RustProxy restrictions **always** apply | Same |
|
||||
| Static-file cookie-ignore allowlist, custom bypass/force rules, TTL caps, BAN/PURGE, request collapse, compression/transform, HOT/COLD, tenant isolation | Unchanged RustProxy mechanisms | Same |
|
||||
|
||||
For `/ui/style.css` with `Cache-Control: public, max-age=600` and **no** origin ETag/Last-Modified, a hard reload with `Cache-Control: no-cache` should now remain `HIT` while its cached representation is fresh. The request headers are *not* stripped before forwarding when an origin fetch actually occurs; RustProxy only ignores them for its own lookup/freshness checks. Client `If-None-Match`/`If-Modified-Since`, range conditions, URL query, `Host` and `Vary` are preserved. Strict mode remains available for installations requiring clients to force validation.
|
||||
|
||||
This is **a documented policy subset, not a Varnish binary/VCL clone**. RustProxy deliberately keeps an explicit zero-by-default fallback TTL (no implicit Varnish 120s TTL), configured cookie exceptions, multi-tenant security, stale prohibitions for `must-revalidate`, and no Varnish-style hit-for-miss/hit-for-pass markers. Not every Varnish configuration behaves like the default built-in VCL. Cookies continue to be omitted from the cache key *only* for the already-configured static-file exception; do not enable that exception for personalized static endpoints. A no-cache **origin response** must not be made cacheable merely to gain HITs.
|
||||
|
||||
Use a three-request GET comparison with `curl` (replace URL with your static resource):
|
||||
|
||||
```bash
|
||||
URL=https://example.com/ui/style.css
|
||||
curl -sS --compressed -D - -o /dev/null "$URL" | grep -iE '^(HTTP/|age:|x-cache:|x-cache-hits:|x-cache-reason:)'
|
||||
curl -sS --compressed -H 'Cache-Control: no-cache' -H 'Pragma: no-cache' -D - -o /dev/null "$URL" | grep -iE '^(HTTP/|age:|x-cache:|x-cache-hits:|x-cache-reason:)'
|
||||
curl -sS --compressed -D - -o /dev/null "$URL" | grep -iE '^(HTTP/|age:|x-cache:|x-cache-hits:|x-cache-reason:)'
|
||||
```
|
||||
|
||||
Enable diagnostic headers if needed. With compatibility **on**, the middle response should be `HIT`, and Age should not reset on a fresh object. With compatibility **off**, it can be `MISS` and reset if no origin validator is available. Explicit PURGE/BAN and stale/expired TTL remain authoritative.
|
||||
|
||||
## Vhost editor options
|
||||
|
||||
@@ -31,7 +61,7 @@ In **Vhosts → Cache**, overrides for static extensions, bypass path prefixes a
|
||||
| `BYPASS` | Cache was disabled or a policy intentionally skipped it (for example authorization, cookies or a path exclusion). |
|
||||
| Revalidated | An existing representation was checked against the origin; a `304` can retain the body. |
|
||||
|
||||
`Age` is total HTTP age, not only the time spent in RustProxy. The optional `X-Cache-Resident-Age` reports the cache residency interval. Debug headers such as `X-Cache`, `X-Cache-Hits` and reason labels are optional and should be enabled deliberately. Browser hard reloads commonly force revalidation, so test with `curl` when investigating.
|
||||
`Age` is total HTTP age, not only the time spent in RustProxy. The optional `X-Cache-Resident-Age` reports the cache residency interval. Debug headers such as `X-Cache`, `X-Cache-Hits` and reason labels are optional and should be enabled deliberately. With `varnish_compatible=true`, browser hard reloads do not force revalidation while an object remains fresh. In strict mode hard reloads can force origin revalidation; compare with `curl` when investigating.
|
||||
|
||||
Example, replacing the listener and Host values with yours:
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
Most settings are managed in the authenticated panel. Save changes after validation; use **Configuration history** to compare or restore an earlier revision. Some listeners are process-owned and require restart to change. Configuration updates are not a replacement for encrypted full backups.
|
||||
|
||||
> Cache compatibility: **Settings → Cache → Varnish-compatible cache policy** (`cache.varnish_compatible`) defaults to `true` in 0.34.7, also for configs without the field. Turning it off restores legacy client freshness handling. See [HTTP cache](CACHE.md#varnish-compatible-cache-policy-0347) for semantics and safety exceptions.
|
||||
|
||||
## Configuration storage: SQLite or JSON file
|
||||
|
||||
**Settings → Manual config** shows the active storage mode and path, sourced from the read-only `storage` member of the authenticated `GET /api/config` response (`revision`, `config`, `storage`). With no `--config`, the authoritative configuration is in `<data-dir>/config.sqlite3` (normally `/var/lib/rustproxy/config.sqlite3`). With `--config`, that JSON file is authoritative, while SQLite still stores revision history, accounts and audit records. Switching modes requires a service restart; the panel does not change the startup argument.
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
# RustProxy documentation
|
||||
|
||||
Practical guides for **RustProxy 0.34.6**. This index and the listed pages are also available in the authenticated panel at **`/docs → Reader`**. The adjacent **API** tab provides the embedded OpenAPI reference. Paths below are links to actual files in the source archive.
|
||||
Practical guides for **RustProxy 0.34.7**. This index and the listed pages are also available in the authenticated panel at **`/docs → Reader`**. The adjacent **API** tab provides the embedded OpenAPI reference. Paths below are links to actual files in the source archive.
|
||||
|
||||
## Getting started
|
||||
|
||||
|
||||
@@ -289,6 +289,8 @@
|
||||
"saveResponse": "Apply response settings",
|
||||
"cacheSettings": "Cache",
|
||||
"enableCache": "Enable cache",
|
||||
"cacheVarnishCompatible": "Varnish-compatible cache policy (recommended; enabled by default)",
|
||||
"cacheVarnishCompatibleHelp": "On: ignore client Cache-Control/Pragma when looking up cached objects. Shift+F5, no-cache, max-age=0 and only-if-cached cannot force an origin fetch while a fresh HIT exists. Respect origin private/no-store/no-cache and Surrogate-Control no-store; do not cache responses with zero remaining TTL; permit up to 10 s grace for eligible stale entries. Keep RustProxy static-cookie exceptions, Authorization, Vary, explicit TTL, invalidation, transforms and HOT/COLD unchanged. Off: original strict client cache directives. Changing modes invalidates existing cached objects. This is not full Varnish VCL emulation.",
|
||||
"cacheSafety": "Complete public-safe GET responses are cached. Authorization, cookies and private/no-store responses still bypass. One byte range can be served from a complete cached object; multipart/unsupported ranges pass through.",
|
||||
"cacheMemory": "HOT allocated budget (MiB)",
|
||||
"cacheObject": "Maximum object (KiB)",
|
||||
|
||||
@@ -289,6 +289,8 @@
|
||||
"saveResponse": "Zastosuj ustawienia odpowiedzi",
|
||||
"cacheSettings": "Cache",
|
||||
"enableCache": "Włącz cache",
|
||||
"cacheVarnishCompatible": "Polityka cache zgodna z Varnish (zalecana; domyślnie włączona)",
|
||||
"cacheVarnishCompatibleHelp": "Włączona: ignoruje Cache-Control/Pragma klienta przy odczycie cache. Shift+F5, no-cache, max-age=0 i only-if-cached nie wymuszają pobrania z backendu, jeśli obiekt jest świeży. Nadal blokuje cache dla private/no-store/no-cache i Surrogate-Control: no-store backendu oraz odpowiedzi bez pozostałego TTL. Dla uprawnionych wygasłych obiektów dopuszcza do 10 s grace z odświeżaniem w tle. Zachowuje wyjątki cookies plików statycznych, Authorization, Vary, limity TTL, unieważnianie, transformacje i HOT/COLD. Wyłączona: dotychczasowa ścisła polityka dyrektyw klienta. Zmiana trybu unieważnia aktualne obiekty cache. To nie jest pełna emulacja VCL Varnish.",
|
||||
"cacheSafety": "Cache zapisuje kompletne, bezpieczne odpowiedzi GET. Authorization, cookies oraz odpowiedzi private/no-store nadal omijają cache. Pojedynczy zakres bajtów może być obsłużony z pełnego obiektu cache; multipart i nieobsługiwane zakresy przechodzą do originu.",
|
||||
"cacheMemory": "Limit alokowanej pamięci HOT (MiB)",
|
||||
"cacheObject": "Limit obiektu (KiB)",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"openapi": "3.0.3",
|
||||
"info": {
|
||||
"title": "RustProxy Administration API",
|
||||
"version": "0.34.6",
|
||||
"version": "0.34.7",
|
||||
"description": "Administration API for the active panel origin. Sign in through the panel; the same-origin HttpOnly cookie authenticates all private operations. Mutations also require the exact Origin, X-RustProxy-Request: 1 and a session-bound X-CSRF-Token. Loopback HTTP is the default; Settings can enable HTTPS before using a non-loopback administration bind. This document contains no live configuration or credentials. Object schemas marked extensible are summaries: full configuration validation is authoritative in Rust. The API also permits explicitly scoped GeneralApiBearer tokens on a narrow route allowlist, with RO/RW and source CIDR checks; API-token management and Prometheus-token management are browser-session-only."
|
||||
},
|
||||
"servers": [
|
||||
@@ -2061,6 +2061,11 @@
|
||||
"maxLength": 64
|
||||
},
|
||||
"default": []
|
||||
},
|
||||
"varnish_compatible": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Default true: Varnish-style request cache policy (ignore client Cache-Control/Pragma directives including no-cache, max-age=0, only-if-cached); reject origin no-cache, Surrogate-Control no-store and nonpositive remaining TTL; 10-second stale-while-revalidate grace for eligible stored objects. Existing RustProxy privacy, cookies, Vary, explicit TTL and invalidation options remain in force. False restores strict client-cache directive handling; switching modes invalidates cache; not full VCL emulation."
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
@@ -13683,4 +13688,4 @@
|
||||
}
|
||||
},
|
||||
"tags": []
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@ function renderSettings() {
|
||||
$("compress-min").value = compression.min_bytes ?? 1024; syncServerMode();
|
||||
}
|
||||
if (!settingsDirty.has("cache-form")) {
|
||||
const c = config.cache || {}; $("cache-enabled").checked = !!c.enabled; $("cache-memory").value = (c.max_bytes ?? 268435456) / 1048576;
|
||||
const c = config.cache || {}; $("cache-enabled").checked = !!c.enabled; $("cache-varnish-compatible").checked = c.varnish_compatible !== false; $("cache-memory").value = (c.max_bytes ?? 268435456) / 1048576;
|
||||
$("cache-transient-memory").value = (c.transient_max_bytes ?? 67108864) / 1048576;
|
||||
$("cache-object").value = (c.max_object_bytes ?? 16777216) / 1024; $("cache-entries").value = c.max_entries ?? 4096;
|
||||
$("cache-eviction-limit").value = c.hot_eviction_max_objects ?? 64;
|
||||
@@ -286,7 +286,7 @@ bindSettingsForm("response-form", next => {
|
||||
next.compression = { min_bytes: Number($("compress-min").value) }; for (const name of ["gzip", "br", "zstd", "deflate"]) next.compression[name] = $(`compress-${name}`).checked;
|
||||
}, "response", next => ({ server_header: next.server_header, diagnostic_headers: next.diagnostic_headers, compression: next.compression }));
|
||||
bindSettingsForm("cache-form", next => {
|
||||
next.cache = { ...(next.cache || {}), enabled: $("cache-enabled").checked, memory_preset: selectedCacheMemoryPreset, max_bytes: Math.round(Number($("cache-memory").value) * 1048576), transient_max_bytes: Math.round(Number($("cache-transient-memory").value) * 1048576), max_object_bytes: Number($("cache-object").value) * 1024, max_entries: Number($("cache-entries").value), hot_eviction_max_objects: Number($("cache-eviction-limit").value), hot_auto_trim_enabled: $("cache-auto-trim-enabled").checked, hot_auto_trim_after_seconds: Number($("cache-auto-trim-after").value), hot_auto_trim_target_percent: Number($("cache-auto-trim-target").value), cold_enabled: $("cache-cold-enabled").checked, cold_preset: selectedCacheColdPreset, cold_path: $("cache-cold-path").value.trim(), cold_max_bytes: Math.round(Number($("cache-cold-bytes").value) * 1048576), cold_max_entries: Number($("cache-cold-entries").value), cold_queue_max_bytes: Math.round(Number($("cache-cold-queue-bytes").value) * 1048576), cold_gc_interval_seconds: Number($("cache-cold-gc-interval").value), cold_gc_max_delete: Number($("cache-cold-gc-max-delete").value), cold_after_seconds: Number($("cache-cold-after").value), cold_max_hot_seconds: Number($("cache-cold-max-hot").value), cold_on_idle: $("cache-cold-on-idle").checked, cold_on_age: $("cache-cold-on-age").checked, cold_on_lru: $("cache-cold-on-lru").checked, cold_on_shutdown: $("cache-cold-on-shutdown").checked, max_ttl_seconds: Number($("cache-ttl").value), default_ttl_seconds: Number($("cache-default-ttl").value), collapse_enabled: $("cache-collapse-enabled").checked, collapse_wait_timeout_ms: Number($("cache-collapse-timeout").value), collapse_timeout_fallback: $("cache-collapse-fallback").value, stale_if_error_timeout: $("cache-sie-timeout").checked, stale_if_error_connection: $("cache-sie-connection").checked, stale_if_error_dns: $("cache-sie-dns").checked, stale_if_error_tls: $("cache-sie-tls").checked, stale_if_error_statuses: $("cache-sie-statuses").value.split(/[\s,]+/).filter(Boolean).map(Number), proactive_refresh_enabled: $("cache-proactive-enabled").checked, proactive_refresh_before_expiry_seconds: Number($("cache-proactive-before").value), proactive_refresh_percent: Number($("cache-proactive-percent").value), proactive_refresh_max_inflight: Number($("cache-proactive-inflight").value), bypass_query: $("cache-query").checked, bypass_prefixes: $("cache-prefixes").value.split(/\r?\n/).map(v => v.trim()).filter(Boolean), http_invalidation_allowed_cidrs: $("cache-http-invalidation-cidrs").value.split(/[\n,]+/).map(v => v.trim()).filter(Boolean), static_ignore_cookies: $("cache-static-cookie").checked, static_extensions: $("cache-static-extensions").value.split(/[\n,]+/).map(v => v.trim().replace(/^\./, "").toLowerCase()).filter(Boolean), expose_status: $("cache-status-header").checked, expose_hits: $("cache-hits-header").checked, expose_cache_status: $("cache-rfc-header").checked, expose_resident_age: $("cache-resident-age-header").checked, expose_only_hits: $("cache-only-hits").checked, via_header: $("cache-via-enabled").checked ? $("cache-via-value").value.trim() : null };
|
||||
next.cache = { ...(next.cache || {}), enabled: $("cache-enabled").checked, varnish_compatible: $("cache-varnish-compatible").checked, memory_preset: selectedCacheMemoryPreset, max_bytes: Math.round(Number($("cache-memory").value) * 1048576), transient_max_bytes: Math.round(Number($("cache-transient-memory").value) * 1048576), max_object_bytes: Number($("cache-object").value) * 1024, max_entries: Number($("cache-entries").value), hot_eviction_max_objects: Number($("cache-eviction-limit").value), hot_auto_trim_enabled: $("cache-auto-trim-enabled").checked, hot_auto_trim_after_seconds: Number($("cache-auto-trim-after").value), hot_auto_trim_target_percent: Number($("cache-auto-trim-target").value), cold_enabled: $("cache-cold-enabled").checked, cold_preset: selectedCacheColdPreset, cold_path: $("cache-cold-path").value.trim(), cold_max_bytes: Math.round(Number($("cache-cold-bytes").value) * 1048576), cold_max_entries: Number($("cache-cold-entries").value), cold_queue_max_bytes: Math.round(Number($("cache-cold-queue-bytes").value) * 1048576), cold_gc_interval_seconds: Number($("cache-cold-gc-interval").value), cold_gc_max_delete: Number($("cache-cold-gc-max-delete").value), cold_after_seconds: Number($("cache-cold-after").value), cold_max_hot_seconds: Number($("cache-cold-max-hot").value), cold_on_idle: $("cache-cold-on-idle").checked, cold_on_age: $("cache-cold-on-age").checked, cold_on_lru: $("cache-cold-on-lru").checked, cold_on_shutdown: $("cache-cold-on-shutdown").checked, max_ttl_seconds: Number($("cache-ttl").value), default_ttl_seconds: Number($("cache-default-ttl").value), collapse_enabled: $("cache-collapse-enabled").checked, collapse_wait_timeout_ms: Number($("cache-collapse-timeout").value), collapse_timeout_fallback: $("cache-collapse-fallback").value, stale_if_error_timeout: $("cache-sie-timeout").checked, stale_if_error_connection: $("cache-sie-connection").checked, stale_if_error_dns: $("cache-sie-dns").checked, stale_if_error_tls: $("cache-sie-tls").checked, stale_if_error_statuses: $("cache-sie-statuses").value.split(/[\s,]+/).filter(Boolean).map(Number), proactive_refresh_enabled: $("cache-proactive-enabled").checked, proactive_refresh_before_expiry_seconds: Number($("cache-proactive-before").value), proactive_refresh_percent: Number($("cache-proactive-percent").value), proactive_refresh_max_inflight: Number($("cache-proactive-inflight").value), bypass_query: $("cache-query").checked, bypass_prefixes: $("cache-prefixes").value.split(/\r?\n/).map(v => v.trim()).filter(Boolean), http_invalidation_allowed_cidrs: $("cache-http-invalidation-cidrs").value.split(/[\n,]+/).map(v => v.trim()).filter(Boolean), static_ignore_cookies: $("cache-static-cookie").checked, static_extensions: $("cache-static-extensions").value.split(/[\n,]+/).map(v => v.trim().replace(/^\./, "").toLowerCase()).filter(Boolean), expose_status: $("cache-status-header").checked, expose_hits: $("cache-hits-header").checked, expose_cache_status: $("cache-rfc-header").checked, expose_resident_age: $("cache-resident-age-header").checked, expose_only_hits: $("cache-only-hits").checked, via_header: $("cache-via-enabled").checked ? $("cache-via-value").value.trim() : null };
|
||||
}, "cache");
|
||||
bindSettingsForm("transform-form", next => {
|
||||
next.transform = {
|
||||
|
||||
@@ -2210,6 +2210,9 @@
|
||||
Authorization, cookies and private/no-store responses still bypass the cache.
|
||||
One byte range can be served from a complete cached object;
|
||||
multipart/unsupported ranges pass through.</p>
|
||||
<label class="check"><input id="cache-varnish-compatible" type="checkbox" /><span
|
||||
data-i18n="cacheVarnishCompatible">Varnish-compatible cache policy (recommended; enabled by default)</span></label>
|
||||
<p class="fine" data-i18n="cacheVarnishCompatibleHelp">When enabled, client Cache-Control and Pragma are ignored for cache lookup: Shift+F5/no-cache/max-age=0 does not replace a fresh HIT or reset its Age. Response private/no-store/no-cache and Surrogate-Control no-store stay uncacheable, responses with no remaining TTL stay out of cache, and eligible expired objects may use up to 10 seconds of background-refresh grace. Existing static-cookie exceptions, Authorization protection, Vary, explicit TTL limits, BAN/PURGE, HOT/COLD, transforms and unsafe-force rules remain independent. Off restores the previous strict client HTTP caching policy. Changing modes invalidates stored objects. This is not full Varnish VCL emulation.</p>
|
||||
<div class="card soft-card cache-memory-sizing">
|
||||
<div class="card-heading">
|
||||
<h3 data-i18n="cacheMemorySizingTitle">Memory sizing</h3>
|
||||
|
||||
Vendored
+3
@@ -6,9 +6,12 @@ mod tests {
|
||||
h.insert("cache-control", value.parse().unwrap());
|
||||
h
|
||||
}
|
||||
// Legacy-policy regression tests explicitly opt out of the new 0.34.7
|
||||
// default; varnish-compatible behavior has its own test module.
|
||||
fn settings() -> Settings {
|
||||
Settings {
|
||||
enabled: true,
|
||||
varnish_compatible: false,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -103,7 +103,7 @@ mod dashboard_tests {
|
||||
}
|
||||
#[test]
|
||||
fn bypass_reasons_are_fixed_and_private_inputs_are_not_echoed() {
|
||||
let settings = Settings::default();
|
||||
let settings = Settings { varnish_compatible: false, ..Settings::default() };
|
||||
let mut headers = HeaderMap::new();
|
||||
headers.insert("cookie", HeaderValue::from_static("session=very-private"));
|
||||
assert_eq!(
|
||||
|
||||
Vendored
+3
-3
@@ -40,7 +40,7 @@ impl Cache {
|
||||
entry.must_revalidate,
|
||||
entry.proxy_revalidate,
|
||||
entry.requires_revalidation,
|
||||
&ticket.request_headers,
|
||||
ticket.freshness_headers(),
|
||||
);
|
||||
if state.servable() {
|
||||
let sequence = store.next_sequence();
|
||||
@@ -144,7 +144,7 @@ impl Cache {
|
||||
entry.must_revalidate,
|
||||
entry.proxy_revalidate,
|
||||
entry.requires_revalidation,
|
||||
&ticket.request_headers,
|
||||
ticket.freshness_headers(),
|
||||
);
|
||||
if !state.servable() {
|
||||
return None;
|
||||
@@ -217,7 +217,7 @@ impl Cache {
|
||||
entry.must_revalidate,
|
||||
entry.proxy_revalidate,
|
||||
entry.requires_revalidation,
|
||||
&ticket.request_headers,
|
||||
ticket.freshness_headers(),
|
||||
);
|
||||
if !state.servable() {
|
||||
return None;
|
||||
|
||||
Vendored
+1
@@ -88,6 +88,7 @@ pub struct Ticket {
|
||||
target: String,
|
||||
key: Key,
|
||||
request_headers: HeaderMap,
|
||||
freshness_headers: Option<HeaderMap>,
|
||||
generation: u64,
|
||||
revision: u64,
|
||||
scope: String,
|
||||
|
||||
Vendored
+3
@@ -87,6 +87,8 @@ pub enum ColdPreset {
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct Settings {
|
||||
pub enabled: bool,
|
||||
/// Ignore client freshness directives on cache lookups, like Varnish builtin VCL.
|
||||
pub varnish_compatible: bool,
|
||||
pub memory_preset: Option<MemoryPreset>,
|
||||
pub max_bytes: usize,
|
||||
pub max_object_bytes: usize,
|
||||
@@ -140,6 +142,7 @@ impl Default for Settings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
enabled: true,
|
||||
varnish_compatible: true,
|
||||
memory_preset: None,
|
||||
max_bytes: 256 * 1024 * 1024,
|
||||
max_object_bytes: 16 * 1024 * 1024,
|
||||
|
||||
Vendored
+46
-1
@@ -44,6 +44,21 @@ fn directives(headers: &HeaderMap) -> Option<HashMap<String, Option<String>>> {
|
||||
}
|
||||
Some(result)
|
||||
}
|
||||
pub fn request_freshness_headers<'a>(
|
||||
headers: &'a HeaderMap,
|
||||
settings: &Settings,
|
||||
) -> std::borrow::Cow<'a, HeaderMap> {
|
||||
if !settings.varnish_compatible
|
||||
|| (!headers.contains_key("cache-control") && !headers.contains_key("pragma"))
|
||||
{
|
||||
return std::borrow::Cow::Borrowed(headers);
|
||||
}
|
||||
let mut freshness = headers.clone();
|
||||
freshness.remove("cache-control");
|
||||
freshness.remove("pragma");
|
||||
std::borrow::Cow::Owned(freshness)
|
||||
}
|
||||
|
||||
pub fn only_if_cached(headers: &HeaderMap) -> bool {
|
||||
headers
|
||||
.get_all("cache-control")
|
||||
@@ -158,6 +173,11 @@ pub fn request_policy(
|
||||
return RequestPolicy::Bypass(reason);
|
||||
}
|
||||
}
|
||||
// Varnish builtin.vcl performs a cache lookup without interpreting
|
||||
// client Cache-Control or Pragma. Security bypasses above still apply.
|
||||
if settings.varnish_compatible {
|
||||
return RequestPolicy::Use;
|
||||
}
|
||||
let Some(control) = directives(headers) else {
|
||||
return RequestPolicy::Bypass("request_cache_control_invalid");
|
||||
};
|
||||
@@ -346,7 +366,24 @@ pub fn varies_on(headers: &HeaderMap, wanted: &str) -> bool {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn response_reason(status: StatusCode, headers: &HeaderMap) -> &'static str {
|
||||
pub fn surrogate_no_store(headers: &HeaderMap) -> bool {
|
||||
headers.get_all("surrogate-control").iter().any(|value| {
|
||||
value.to_str().ok().is_some_and(|text| {
|
||||
text.split([',', ';']).any(|part| {
|
||||
part.trim()
|
||||
.split_once('=')
|
||||
.map_or(part.trim(), |(key, _)| key.trim())
|
||||
.eq_ignore_ascii_case("no-store")
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
pub fn response_reason(
|
||||
status: StatusCode,
|
||||
headers: &HeaderMap,
|
||||
settings: &Settings,
|
||||
) -> &'static str {
|
||||
if status != StatusCode::OK {
|
||||
return "response_status";
|
||||
}
|
||||
@@ -367,6 +404,14 @@ pub fn response_reason(status: StatusCode, headers: &HeaderMap) -> &'static str
|
||||
return "response_cache_control";
|
||||
}
|
||||
}
|
||||
if settings.varnish_compatible {
|
||||
if control.contains_key("no-cache") {
|
||||
return "response_cache_control";
|
||||
}
|
||||
if surrogate_no_store(headers) {
|
||||
return "response_surrogate_control";
|
||||
}
|
||||
}
|
||||
for value in headers.get_all("vary") {
|
||||
if value.to_str().ok().is_none_or(|value| {
|
||||
value.split(',').any(|name| {
|
||||
|
||||
Vendored
+21
-1
@@ -92,6 +92,14 @@ pub fn plan(
|
||||
{
|
||||
return None;
|
||||
}
|
||||
// Varnish builtin.vcl treats these as uncacheable origin responses
|
||||
// (hit-for-miss is not implemented by RustProxy). Never weaken private
|
||||
// or no-store handling even if Surrogate-Control is also present.
|
||||
if settings.varnish_compatible
|
||||
&& (control.contains_key("no-cache") || surrogate_no_store(headers))
|
||||
{
|
||||
return None;
|
||||
}
|
||||
let requires_revalidation = control.contains_key("no-cache");
|
||||
let must_revalidate = control.contains_key("must-revalidate");
|
||||
let proxy_revalidate = control.contains_key("proxy-revalidate");
|
||||
@@ -102,7 +110,7 @@ pub fn plan(
|
||||
Some(None) => None,
|
||||
}
|
||||
};
|
||||
let stale_while_revalidate = parse_window("stale-while-revalidate")?;
|
||||
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")
|
||||
@@ -148,6 +156,18 @@ pub fn plan(
|
||||
None if requires_revalidation => 0,
|
||||
None => return None,
|
||||
};
|
||||
// Like Varnish's built-in VCL, a backend response with no remaining
|
||||
// freshness is not a reusable shared object (Varnish stores a hit-for-miss
|
||||
// marker instead; RustProxy does not implement those markers).
|
||||
if settings.varnish_compatible && initial_age.as_secs() >= ttl {
|
||||
return None;
|
||||
}
|
||||
// Varnish defaults to ten seconds of grace after a *positive* TTL.
|
||||
// Keep RustProxy's existing must-revalidate/proxy-revalidate safety checks;
|
||||
// never turn a no-cache or zero-TTL response into a grace HIT.
|
||||
if settings.varnish_compatible && stale_while_revalidate == 0 {
|
||||
stale_while_revalidate = 10;
|
||||
}
|
||||
if !requires_revalidation
|
||||
&& initial_age.as_secs()
|
||||
>= retention_deadline(
|
||||
|
||||
Vendored
+3
@@ -18,3 +18,6 @@ include!("invalidation/http_invalidation_tests.rs");
|
||||
|
||||
#[cfg(test)]
|
||||
include!("lookup/hot_hit_034_tests.rs");
|
||||
|
||||
#[cfg(test)]
|
||||
include!("varnish_compatible_tests.rs");
|
||||
Vendored
+22
@@ -101,6 +101,7 @@ impl Cache {
|
||||
target: target.to_owned(),
|
||||
key,
|
||||
request_headers: headers.clone(),
|
||||
freshness_headers: None,
|
||||
generation: store.generation,
|
||||
revision,
|
||||
scope: scope.to_owned(),
|
||||
@@ -392,3 +393,24 @@ impl Cache {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Ticket {
|
||||
/// In Varnish compatibility mode, request cache directives do not constrain
|
||||
/// freshness. Keep original headers for Vary and downstream conditionals.
|
||||
pub fn with_varnish_compatible(mut self, compatible: bool) -> Self {
|
||||
if compatible
|
||||
&& (self.request_headers.contains_key("cache-control")
|
||||
|| self.request_headers.contains_key("pragma"))
|
||||
{
|
||||
let mut freshness = self.request_headers.clone();
|
||||
freshness.remove("cache-control");
|
||||
freshness.remove("pragma");
|
||||
self.freshness_headers = Some(freshness);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
fn freshness_headers(&self) -> &HeaderMap {
|
||||
self.freshness_headers.as_ref().unwrap_or(&self.request_headers)
|
||||
}
|
||||
}
|
||||
+158
@@ -0,0 +1,158 @@
|
||||
mod varnish_compatible_tests {
|
||||
use super::*;
|
||||
use http_body_util::BodyExt;
|
||||
|
||||
fn headers(cache_control: &str) -> HeaderMap {
|
||||
let mut h = HeaderMap::new();
|
||||
h.insert("cache-control", HeaderValue::from_str(cache_control).unwrap());
|
||||
h
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn default_and_legacy_serialization_are_explicit() {
|
||||
assert!(Settings::default().varnish_compatible);
|
||||
let legacy: Settings = serde_json::from_str(r#"{"enabled":true}"#).unwrap();
|
||||
assert!(legacy.varnish_compatible);
|
||||
let strict: Settings = serde_json::from_str(r#"{"varnish_compatible":false}"#).unwrap();
|
||||
assert!(!strict.varnish_compatible);
|
||||
let enabled = serde_json::to_value(&legacy).unwrap();
|
||||
assert_eq!(enabled["varnish_compatible"], true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn client_freshness_is_ignored_only_in_varnish_mode() {
|
||||
let mut compatible = Settings::default();
|
||||
let directives = [
|
||||
"no-cache", "no-store", "max-age=0", "max-age=1",
|
||||
"min-fresh=600", "max-stale=9999", "only-if-cached", "invalid directive",
|
||||
];
|
||||
for value in directives {
|
||||
let h = headers(value);
|
||||
assert_eq!(
|
||||
request_policy(&Method::GET, &h, true, "/style.css", false, &compatible),
|
||||
RequestPolicy::Use,
|
||||
"varnish mode should ignore client directive: {value}"
|
||||
);
|
||||
let freshness = request_freshness_headers(&h, &compatible);
|
||||
assert!(!freshness.contains_key("cache-control"));
|
||||
assert!(h.contains_key("cache-control"), "do not mutate origin request headers");
|
||||
}
|
||||
let mut pragma = HeaderMap::new();
|
||||
pragma.insert("pragma", HeaderValue::from_static("no-cache"));
|
||||
assert_eq!(request_policy(&Method::GET, &pragma, true, "/", false, &compatible), RequestPolicy::Use);
|
||||
assert!(!request_freshness_headers(&pragma, &compatible).contains_key("pragma"));
|
||||
compatible.varnish_compatible = false;
|
||||
assert_eq!(request_policy(&Method::GET, &headers("no-cache"), true, "/", false, &compatible), RequestPolicy::Revalidate("request_no_cache"));
|
||||
assert_eq!(request_policy(&Method::GET, &headers("no-store"), true, "/", false, &compatible), RequestPolicy::Bypass("request_no_store"));
|
||||
assert!(only_if_cached(&headers("only-if-cached")), "strict-only 504 guard still recognizes directive");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn vcl_style_request_lookup_preserves_privacy_and_local_rules() {
|
||||
let mut settings = Settings::default();
|
||||
for (name, value) in [
|
||||
("authorization", "Bearer private"),
|
||||
("cookie", "session=private"),
|
||||
("if-match", "\"etag\""),
|
||||
("upgrade", "websocket"),
|
||||
] {
|
||||
let mut h = headers("no-cache");
|
||||
h.insert(http::HeaderName::from_bytes(name.as_bytes()).unwrap(), HeaderValue::from_str(value).unwrap());
|
||||
assert!(matches!(request_policy(&Method::GET, &h, true, "/index.html", false, &settings), RequestPolicy::Bypass(_)));
|
||||
}
|
||||
settings.bypass_query = true;
|
||||
assert_eq!(request_policy(&Method::GET, &HeaderMap::new(), true, "/style.css", true, &settings), RequestPolicy::Bypass("query_excluded"));
|
||||
settings.bypass_query = false;
|
||||
settings.bypass_prefixes = vec!["/private".into()];
|
||||
assert_eq!(request_policy(&Method::GET, &HeaderMap::new(), true, "/private/account", false, &settings), RequestPolicy::Bypass("path_excluded"));
|
||||
assert_eq!(request_policy(&Method::POST, &HeaderMap::new(), true, "/style.css", false, &settings), RequestPolicy::Bypass("request_method"));
|
||||
assert!(settings.ignore_cookie_for_path("/style.css"), "existing static cookie feature remains enabled");
|
||||
assert!(!settings.ignore_cookie_for_path("/index.html"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn backend_response_policy_matches_varnish_without_weakening_privacy() {
|
||||
let compatible = Settings::default();
|
||||
let mut strict = compatible.clone();
|
||||
strict.varnish_compatible = false;
|
||||
for control in ["private, max-age=60", "no-store, max-age=60"] {
|
||||
assert!(plan(StatusCode::OK, &headers(control), &compatible, Duration::ZERO).is_none());
|
||||
assert!(plan(StatusCode::OK, &headers(control), &strict, Duration::ZERO).is_none());
|
||||
}
|
||||
let mut no_cache = headers("no-cache, max-age=60");
|
||||
no_cache.insert("etag", HeaderValue::from_static("\"origin\""));
|
||||
assert!(plan(StatusCode::OK, &no_cache, &compatible, Duration::ZERO).is_none());
|
||||
assert!(plan(StatusCode::OK, &no_cache, &strict, Duration::ZERO).is_some());
|
||||
assert_eq!(response_reason(StatusCode::OK, &no_cache, &compatible), "response_cache_control");
|
||||
let mut surrogate = headers("public, max-age=60");
|
||||
surrogate.insert("surrogate-control", HeaderValue::from_static("max-age=120; NO-STORE"));
|
||||
assert!(plan(StatusCode::OK, &surrogate, &compatible, Duration::ZERO).is_none());
|
||||
assert_eq!(response_reason(StatusCode::OK, &surrogate, &compatible), "response_surrogate_control");
|
||||
assert!(plan(StatusCode::OK, &surrogate, &strict, Duration::ZERO).is_some());
|
||||
for control in ["max-age=0", "max-age=60, s-maxage=0"] {
|
||||
assert!(plan(StatusCode::OK, &headers(control), &compatible, Duration::ZERO).is_none());
|
||||
assert!(plan(StatusCode::OK, &headers(control), &strict, Duration::ZERO).is_some());
|
||||
}
|
||||
let mut cookie = headers("max-age=60");
|
||||
cookie.insert("set-cookie", HeaderValue::from_static("session=private"));
|
||||
assert!(plan(StatusCode::OK, &cookie, &compatible, Duration::ZERO).is_none());
|
||||
let mut vary = headers("max-age=60");
|
||||
vary.insert("vary", HeaderValue::from_static("*"));
|
||||
assert!(plan(StatusCode::OK, &vary, &compatible, Duration::ZERO).is_none());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn varnish_style_hard_reload_keeps_hot_hit_and_age_without_origin_validator() {
|
||||
let cache = Cache::new(1);
|
||||
let settings = Settings::default();
|
||||
let ticket = cache.ticket(1, "https", "example.test", "app", "/style.css", &HeaderMap::new()).unwrap();
|
||||
let mut response = Response::new(Body::from("public css"));
|
||||
*response.headers_mut() = headers("public, max-age=600");
|
||||
let plan = plan(StatusCode::OK, response.headers(), &settings, Duration::ZERO).unwrap();
|
||||
cache.wrap(response, ticket.clone(), plan, &settings).into_body().collect().await.unwrap();
|
||||
{
|
||||
let mut store = cache.store.lock().unwrap();
|
||||
for entry in store.entries.values_mut() {
|
||||
entry.received = Instant::now() - Duration::from_secs(45);
|
||||
}
|
||||
}
|
||||
let mut request = headers("no-cache, max-age=0, min-fresh=900");
|
||||
request.insert("pragma", HeaderValue::from_static("no-cache"));
|
||||
let compatibility_ticket = cache.ticket(1, "https", "example.test", "app", "/style.css", &request).unwrap().with_varnish_compatible(true);
|
||||
let first = cache.get(&compatibility_ticket).expect("hard reload should keep a fresh HIT");
|
||||
assert!(first.response.headers().get("age").unwrap().to_str().unwrap().parse::<u64>().unwrap() >= 45);
|
||||
assert_eq!(first.hits, 1);
|
||||
let again = cache.get(&compatibility_ticket).unwrap();
|
||||
assert_eq!(again.hits, 2, "hard reload must not reset HIT counter");
|
||||
assert_eq!(cache.view().entries, 1);
|
||||
let strict = cache.ticket(1, "https", "example.test", "app", "/style.css", &request).unwrap();
|
||||
assert!(cache.get(&strict).is_none(), "strict max-age=0 requires revalidation");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn ten_second_grace_and_no_unconditional_stale_outside_window() {
|
||||
let cache = Cache::new(1);
|
||||
let settings = Settings::default();
|
||||
let ticket = cache.ticket(1, "https", "example.test", "app", "/asset.js", &HeaderMap::new()).unwrap();
|
||||
let mut response = Response::new(Body::from("js"));
|
||||
*response.headers_mut() = headers("public, max-age=60");
|
||||
let plan = plan(StatusCode::OK, response.headers(), &settings, Duration::ZERO).unwrap();
|
||||
assert_eq!(plan.stale_while_revalidate, 10);
|
||||
cache.wrap(response, ticket.clone(), plan, &settings).into_body().collect().await.unwrap();
|
||||
{
|
||||
let mut store = cache.store.lock().unwrap();
|
||||
for entry in store.entries.values_mut() {
|
||||
entry.received = Instant::now() - Duration::from_secs(65);
|
||||
}
|
||||
}
|
||||
let hit = cache.get(&ticket).expect("grace HIT");
|
||||
assert!(hit.stale && hit.background_revalidate);
|
||||
{
|
||||
let mut store = cache.store.lock().unwrap();
|
||||
for entry in store.entries.values_mut() {
|
||||
entry.received = Instant::now() - Duration::from_secs(75);
|
||||
}
|
||||
}
|
||||
assert!(cache.get(&ticket).is_none(), "expired beyond grace does not produce HIT");
|
||||
}
|
||||
}
|
||||
@@ -178,7 +178,8 @@ let original_policy = cache_plan.request_policy(
|
||||
);
|
||||
|
||||
let only_cached =
|
||||
cache_settings.active_for(route.cache) && crate::cache::only_if_cached(request.headers());
|
||||
cache_settings.active_for(route.cache) && !cache_settings.varnish_compatible
|
||||
&& crate::cache::only_if_cached(request.headers());
|
||||
let origin_suffix = match route.rewritten_path(&path) {
|
||||
Ok(None) => public_suffix.clone(),
|
||||
Ok(Some(rewritten)) => {
|
||||
@@ -296,7 +297,7 @@ let cache_ticket = if effective_cacheable {
|
||||
cache_route,
|
||||
&public_suffix,
|
||||
key_headers,
|
||||
)
|
||||
).map(|ticket| ticket.with_varnish_compatible(cache_settings.varnish_compatible))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
@@ -308,14 +309,17 @@ let cached_revalidation = if let Some(ticket) = cache_ticket.as_ref() {
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let freshness_headers = crate::cache::request_freshness_headers(
|
||||
&client_conditionals, cache_settings,
|
||||
);
|
||||
let freshness_revalidation_reason = cached_revalidation
|
||||
.as_ref()
|
||||
.and_then(|cached| cached.request_freshness_revalidation_reason(&client_conditionals));
|
||||
.and_then(|cached| cached.request_freshness_revalidation_reason(&freshness_headers));
|
||||
let pending_revalidation = revalidation_reason.is_some()
|
||||
|| freshness_revalidation_reason.is_some()
|
||||
|| cached_revalidation
|
||||
.as_ref()
|
||||
.is_some_and(|cached| !cached.reusable_for_request(&client_conditionals));
|
||||
.is_some_and(|cached| !cached.reusable_for_request(&freshness_headers));
|
||||
let miss_recorded = false;
|
||||
(
|
||||
backend, backend_lease, affinity_cookie, admin_control_plane, cache_settings,
|
||||
|
||||
@@ -130,7 +130,7 @@ let origin_reason = (cache_ticket.is_some() && origin_plan.is_none()).then(|| {
|
||||
if ignore_static_cookie && crate::cache::varies_on(response.headers(), "cookie") {
|
||||
"response_vary_cookie"
|
||||
} else {
|
||||
crate::cache::response_reason(response.status(), response.headers())
|
||||
crate::cache::response_reason(response.status(), response.headers(), cache_settings)
|
||||
}
|
||||
});
|
||||
let origin_no_transform = crate::transform::no_transform(response.headers());
|
||||
|
||||
@@ -64,6 +64,7 @@
|
||||
state.cache.revision(), scope, context.scheme,
|
||||
original_host.to_str().unwrap_or(""), &route.id, &public_suffix,
|
||||
key_headers.as_ref().unwrap_or(&request_headers))
|
||||
.map(|ticket| ticket.with_varnish_compatible(cache_settings.varnish_compatible))
|
||||
} else { None };
|
||||
let range = cache_plan::range_selection(eligible, &request_method, &request_headers);
|
||||
let if_range = if eligible { request_headers.get("if-range").cloned() } else { None };
|
||||
@@ -71,9 +72,12 @@
|
||||
let cached_revalidation = if let Some(ticket) = cache_ticket.as_ref() {
|
||||
state.cache.revalidation_tiered(ticket).await
|
||||
} else { None };
|
||||
let freshness_headers = crate::cache::request_freshness_headers(
|
||||
&request_headers, cache_settings,
|
||||
);
|
||||
let needs_validation = policy.revalidation_reason().is_some()
|
||||
|| cached_revalidation.as_ref().is_some_and(|cached|
|
||||
!cached.reusable_for_request(&request_headers));
|
||||
!cached.reusable_for_request(&freshness_headers));
|
||||
if let Some(ticket) = &cache_ticket {
|
||||
if !needs_validation {
|
||||
if let Some(mut hit) = state.cache.get_tiered(ticket, cache_settings).await {
|
||||
@@ -109,7 +113,8 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
if cache_ticket.is_some() && crate::cache::only_if_cached(&request_headers) {
|
||||
if cache_ticket.is_some() && !cache_settings.varnish_compatible
|
||||
&& crate::cache::only_if_cached(&request_headers) {
|
||||
return error(StatusCode::GATEWAY_TIMEOUT,
|
||||
"RustProxy: only-if-cached request has no usable Web Server representation\n");
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user