This commit is contained in:
Mateusz Gruszczyński committed 2026-11-07 10:23:28 +01:00
1 parent ff42a13dbf
commit e7b4991316
14 files changed
+176 -50

No files matched your search

+1 -1
View File
@@ -1,6 +1,6 @@
# RustProxy source and documentation maintenance # RustProxy source and documentation maintenance
Current source version: **0.35.4**. The Cargo package and binary are named `rust-proxy`. Current source version: **0.35.5**. The Cargo package and binary are named `rust-proxy`.
Before editing, read [README.md](README.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. Before editing, read [README.md](README.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.
+7
View File
@@ -2,6 +2,13 @@
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 the latest release. 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 the latest release.
## 0.35.5 — Overview polish and cache build fix
- **Overview charts:** the cache-results heading now matches the other chart headings and its HIT/MISS/BYPASS legend stays on one line; system uptime is shown in the System load header; the backend count is aligned with Open connections; the redundant Requests per second footer was removed from the PHP requests tile.
- **Polish status labels:** the sidebar healthy-state label is now **SYSTEM OK**, and the application self-check uses the shorter **API** label.
- **Cache build fix:** restored the detached-header helper functions used when finalizing cache fills, fixing the `E0425` build failure for `detached_header_value` and `detach_header_map` while preserving the sensitive flag on copied header values.
- **Upgrade notes:** no configuration or database changes are required.
## 0.35.4 — Dashboard status and control cleanup ## 0.35.4 — Dashboard status and control cleanup
- **Overview samples:** the history sample selector is right-aligned on desktop and mobile and now saves immediately in the browser; the separate Remember choice button is removed. - **Overview samples:** the history sample selector is right-aligned on desktop and mobile and now saves immediately in the browser; the separate Remember choice button is removed.
Generated
+1 -1
View File
@@ -1943,7 +1943,7 @@ dependencies = [
[[package]] [[package]]
name = "rust-proxy" name = "rust-proxy"
version = "0.35.4" version = "0.35.5"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"arc-swap", "arc-swap",
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "rust-proxy" name = "rust-proxy"
version = "0.35.4" version = "0.35.5"
edition = "2021" edition = "2021"
rust-version = "1.99.1" rust-version = "1.99.1"
description = "RustProxy - independent reverse proxy with local administration" description = "RustProxy - independent reverse proxy with local administration"
+13 -13
View File
@@ -1,10 +1,10 @@
61bf40a0572889dc8b0dda9eae4e93e44b0de9364b3c798106c85700ffb37c23 .dockerignore 61bf40a0572889dc8b0dda9eae4e93e44b0de9364b3c798106c85700ffb37c23 .dockerignore
4140a2956264b44f259e6a37fc00ba02097bbe68b09296e04d3d243c1287129b .env.example 4140a2956264b44f259e6a37fc00ba02097bbe68b09296e04d3d243c1287129b .env.example
e76e688874828e3743d03693b1d2872b9633b4db09909673786caf30f7cfe489 .gitignore e76e688874828e3743d03693b1d2872b9633b4db09909673786caf30f7cfe489 .gitignore
f8272b8b6a11d50811e2f25b5d43f4713dd7fc7d22c2b4892cb85757d481c10d AGENTS.md 140ddb17001c2c821dd763335c1cecbfd75b27166b2a3ab1e815a8d53471a856 AGENTS.md
9539278957c4d6dbbe613b7ba5388499e215b28aa153f099eefe4949b3eb4f78 CHANGELOG.md 2feb306d156b92773b6bf376d439c9f823840b745309a61b158ddc68a59186c3 CHANGELOG.md
c593deba438fb6f5acbc6868612ddfa30d4f1e15134e9654c0f399f49b2c32fd Cargo.lock f7c3fa3eb61e00a0ec0156229877a01d14bd3fa568dff0b04d0d73bb12cf6fae Cargo.lock
9795da5b826e58378910a45c3c9d9bb3a9cbdf9e009ad03ee82d1a59da1f4e83 Cargo.toml bf974faca111295d73a0c092be3536d70efeb222d5599f28814cba169cbeef25 Cargo.toml
25c7f3c8162cbf5cc156439774118a81dae9fdc52b611ec7e40c230fc99a772c Dockerfile 25c7f3c8162cbf5cc156439774118a81dae9fdc52b611ec7e40c230fc99a772c Dockerfile
0d96a4ff68ad6d4b6f1f30f713b18d5184912ba8dd389f86aa7710db079abcb0 LICENSE 0d96a4ff68ad6d4b6f1f30f713b18d5184912ba8dd389f86aa7710db079abcb0 LICENSE
82d1dee2fc68158f0ea73259151461e64c8b18d807cd1fecfb1ed99dc30cf5f4 README.md 82d1dee2fc68158f0ea73259151461e64c8b18d807cd1fecfb1ed99dc30cf5f4 README.md
@@ -86,12 +86,12 @@ de6550ab8f48d556d752c252212c38ba65491fd224f972c10fbe552f91ed7520 integrations/o
45be151cd85fc2ef2f1fdc3003ace63381af262e73af8a685ab48cb697cc0de1 integrations/routeros-oci-build/.env.routeros.example 45be151cd85fc2ef2f1fdc3003ace63381af262e73af8a685ab48cb697cc0de1 integrations/routeros-oci-build/.env.routeros.example
11aa102de1089ecc375f20c4bd5420fcfd3b2ef23fe0c8bdf04953fcfaf40ef0 integrations/routeros-oci-build/Dockerfile.routeros 11aa102de1089ecc375f20c4bd5420fcfd3b2ef23fe0c8bdf04953fcfaf40ef0 integrations/routeros-oci-build/Dockerfile.routeros
7c7a3e51f43b43e1c962a4b0bb591f99c1f06977bf77f23719f7f867dfe7eb8e integrations/routeros-oci-build/Dockerfile.routeros.dockerignore 7c7a3e51f43b43e1c962a4b0bb591f99c1f06977bf77f23719f7f867dfe7eb8e integrations/routeros-oci-build/Dockerfile.routeros.dockerignore
a68d5780f9eeb084db5ec465791b71332deb0456fdb245a253d464c5c76431c9 integrations/routeros-oci-build/README.md 70852c6f13ef6a287c8f815aab085cc53e1150461a88342ad83715a9c7b0bbef integrations/routeros-oci-build/README.md
3f092a9ab80221eddd67be4d1a776acbc6e04c1eb6011b588280c28e83b2582f integrations/routeros-oci-build/build-routeros-oci.sh 3f092a9ab80221eddd67be4d1a776acbc6e04c1eb6011b588280c28e83b2582f integrations/routeros-oci-build/build-routeros-oci.sh
3f267cafa16006e5456ade78ee2d5fae02cc7ce747839523068ffd8d7c98798a integrations/routeros-oci-build/docker-entrypoint.sh 3f267cafa16006e5456ade78ee2d5fae02cc7ce747839523068ffd8d7c98798a integrations/routeros-oci-build/docker-entrypoint.sh
13189fa546c3488dddd8efc80c47f6da5241e5fc28b79cbfe795414ea05c7a4f langs/README.md 13189fa546c3488dddd8efc80c47f6da5241e5fc28b79cbfe795414ea05c7a4f langs/README.md
cfe8fff42f98edc85a626f1d87521fa75d24f8b6b4573c46b1541820681a7080 langs/en_US.json cfe8fff42f98edc85a626f1d87521fa75d24f8b6b4573c46b1541820681a7080 langs/en_US.json
771b13ae8d77ec0348cb56a7093d328a8b3abcde184a65a81f5db8e44fb910b3 langs/pl_pl.json 34628bddc76c02eff482aa8300e0523e0edad87dfa4ebc3ef3285d68b6c46cfb langs/pl_pl.json
9664543e4d03422788a65e42f968c1f026c2235cb5be6fc3e0ad318997077538 make_zip.py 9664543e4d03422788a65e42f968c1f026c2235cb5be6fc3e0ad318997077538 make_zip.py
e830d37dd1f81a4b0aa7d535f5bba69e34e433b0fd99cc8ee0b296786c32379a migrations/0002_admin.sql e830d37dd1f81a4b0aa7d535f5bba69e34e433b0fd99cc8ee0b296786c32379a migrations/0002_admin.sql
20112cc82192098b8d602f1c4f7ca08712e9e1366c845fabb92753187c370d35 migrations/0003_certificate_renewals.sql 20112cc82192098b8d602f1c4f7ca08712e9e1366c845fabb92753187c370d35 migrations/0003_certificate_renewals.sql
@@ -162,7 +162,7 @@ d58a2ed83319176de4e66790ed292447c9497ae031464ec55cfe27174acb639a src/admin/file
77b8c05645969834cc8a58e249a7b60a57d6c47ad1c5cd92ffa5e4a9b5a8e73c src/admin/file_logs_query.rs 77b8c05645969834cc8a58e249a7b60a57d6c47ad1c5cd92ffa5e4a9b5a8e73c src/admin/file_logs_query.rs
444d7715406ffd2305a72decf7fdf633aa4c2752cd881c8fa3b95ed971d79820 src/admin/logging_api.rs 444d7715406ffd2305a72decf7fdf633aa4c2752cd881c8fa3b95ed971d79820 src/admin/logging_api.rs
243f4a9c3fa99781e19c3952354d2632c0ce65e1dafac729567cbe3c177f94cb src/admin/mod.rs 243f4a9c3fa99781e19c3952354d2632c0ce65e1dafac729567cbe3c177f94cb src/admin/mod.rs
ee4075f5f16bb0940fb785b2c527669a605d4352efe1030d4ca98bddb1ce051c src/admin/openapi.json 30b0ea16c6960e8efd682e95429c70c1b2ff178aef67e570e678d0dd82dce060 src/admin/openapi.json
1f4ec45d146e00ef664fae37517f8fcb5455d47daec496c02b2fc15ddec49131 src/admin/operations.rs 1f4ec45d146e00ef664fae37517f8fcb5455d47daec496c02b2fc15ddec49131 src/admin/operations.rs
257d93a29d0bda96462bcf695aba8d0ec0f9412c379e066ec46ae8ee034e3a53 src/admin/panel_assets.rs 257d93a29d0bda96462bcf695aba8d0ec0f9412c379e066ec46ae8ee034e3a53 src/admin/panel_assets.rs
f5127855c2994d052678865df36d703b74f4a0afc633daf7718b10da18d26e37 src/admin/panel_content.rs f5127855c2994d052678865df36d703b74f4a0afc633daf7718b10da18d26e37 src/admin/panel_content.rs
@@ -198,7 +198,7 @@ bfd9fafb3112197e8f875dbf87a9a66c81aef0fe83687601a84a66f5e13f69bc src/admin/web/
46c7cd36397375eb7e8c230c8aa97b1dbea0a63800beb977efe1ec67a14b237e src/admin/web/app/preferences.js 46c7cd36397375eb7e8c230c8aa97b1dbea0a63800beb977efe1ec67a14b237e src/admin/web/app/preferences.js
9e2b12d34ab1fb29716645720577ad49b16c03b46c482a03695e8f645d170e79 src/admin/web/app/rate-sampling.js 9e2b12d34ab1fb29716645720577ad49b16c03b46c482a03695e8f645d170e79 src/admin/web/app/rate-sampling.js
d34f9e25a04cc4eafdbc48daa4e69aab18944e8d34e555a50d9c122c680595f8 src/admin/web/app/refresh.js d34f9e25a04cc4eafdbc48daa4e69aab18944e8d34e555a50d9c122c680595f8 src/admin/web/app/refresh.js
564c8d81c9164e3a63f230579facd3c75281a806477e97ef9c05145807e08c94 src/admin/web/app/runtime.js c6ae53c0e95e67b9165822813efc622001be5354c19bb221a52514221d1df23e src/admin/web/app/runtime.js
31201586925e6f4792071d7d03fb05dcc4a69a03c02a4e85eb0746f45af68074 src/admin/web/app/session-resume.js 31201586925e6f4792071d7d03fb05dcc4a69a03c02a4e85eb0746f45af68074 src/admin/web/app/session-resume.js
c7a18238ac426de4d1cf84a395ee4dc66410d60a57a3822695dc10adc668d956 src/admin/web/app/settings.js c7a18238ac426de4d1cf84a395ee4dc66410d60a57a3822695dc10adc668d956 src/admin/web/app/settings.js
b7ead49224a4ec67181d3f24f9d9634bd6d76756f826a4d5d993300637d1d8f3 src/admin/web/app/stream-dashboard.js b7ead49224a4ec67181d3f24f9d9634bd6d76756f826a4d5d993300637d1d8f3 src/admin/web/app/stream-dashboard.js
@@ -208,7 +208,7 @@ e9788a9d1e0bce8775f612a5c842afea8a0dcf01301acdef4b69ff6a52d2ef45 src/admin/web/
a09f060b47771c56e9b9e57f1b896a32a2f87f1fb33401ac76932a91d247c67e src/admin/web/css/00-tokens.css a09f060b47771c56e9b9e57f1b896a32a2f87f1fb33401ac76932a91d247c67e src/admin/web/css/00-tokens.css
77b8b748f31ef383c64ba5ca1740e9b6073f0de1e77c2c8c62d0f38bb52dd296 src/admin/web/css/10-base.css 77b8b748f31ef383c64ba5ca1740e9b6073f0de1e77c2c8c62d0f38bb52dd296 src/admin/web/css/10-base.css
6ed54b27a4a81b073f1d30cf61e366f3d5c1f6f8495f0d0a8af48e061937eb4e src/admin/web/css/20-shell.css 6ed54b27a4a81b073f1d30cf61e366f3d5c1f6f8495f0d0a8af48e061937eb4e src/admin/web/css/20-shell.css
65c1bd6d0adf05de60738f5a557dff18ad0d4b0b531e58aab29b01519416b09c src/admin/web/css/30-overview.css c6d5696f0cdf4149e3341d18f7fd955f2411d50aac49a307c3eb0de2db9f92cb src/admin/web/css/30-overview.css
dd82b5e3ead91c20bb08cf8d71bbba31ea8e3d108c417913c63409f3e34da7e1 src/admin/web/css/40-editors.css dd82b5e3ead91c20bb08cf8d71bbba31ea8e3d108c417913c63409f3e34da7e1 src/admin/web/css/40-editors.css
6af9fcb439823ec63abe2c1dd86c9ecba17c233262fd8ab80d321d64ae2758ab src/admin/web/css/50-settings.css 6af9fcb439823ec63abe2c1dd86c9ecba17c233262fd8ab80d321d64ae2758ab src/admin/web/css/50-settings.css
f8b515c63080c71ee647cfd8c36628271e8357b31cd84f00cf591e9b752b44fe src/admin/web/css/60-monitoring.css f8b515c63080c71ee647cfd8c36628271e8357b31cd84f00cf591e9b752b44fe src/admin/web/css/60-monitoring.css
@@ -245,8 +245,8 @@ cdd390e69ca4cd010262e8fddb653e4097fbcfdc678b081c422edcd68e974f85 src/admin/web/
ac9f667273918e18406df06cb2613c923f50a88897693a03a18f500e22dc6ec2 src/admin/web/login.html ac9f667273918e18406df06cb2613c923f50a88897693a03a18f500e22dc6ec2 src/admin/web/login.html
c2e5f554810b8e34fb47361fb90a01073a2e332ee26d82e030956fad3ec1f83e src/admin/web/login.js c2e5f554810b8e34fb47361fb90a01073a2e332ee26d82e030956fad3ec1f83e src/admin/web/login.js
734aeac4855f0913a84a82d7b5c17b37de4504b50a8701edeb775d6926929bce src/admin/web/management.js 734aeac4855f0913a84a82d7b5c17b37de4504b50a8701edeb775d6926929bce src/admin/web/management.js
4481a592fcce9a2aa1db5e4a25619e19fd459c39039b86c0549dfc427eec1b45 src/admin/web/partials/overview-charts.html 1f3d10e389c9c20e6eb019509fa6e82b50c6b43bbf988c1210a4d42bb73985d0 src/admin/web/partials/overview-charts.html
69296af507dbc8c211800f4841c3d7ad6a2490aad2e93ecb297246b7470e3be3 src/admin/web/partials/overview-metrics.html 2842346eb66569b0aba2938ff0f724b50d21254b2aa0d2c00f6380ad03449b61 src/admin/web/partials/overview-metrics.html
3928afce2ed6d5f2d3e29475dd29e4c3bd3c6df180ad5119beaff0c7a58e3b3b src/admin/web/prometheus-token.js 3928afce2ed6d5f2d3e29475dd29e4c3bd3c6df180ad5119beaff0c7a58e3b3b src/admin/web/prometheus-token.js
2d491fe9a547fe109dc5db6a74806d50b08c3daca15a6622c79c9fea33b10c63 src/admin/web/redirects.js 2d491fe9a547fe109dc5db6a74806d50b08c3daca15a6622c79c9fea33b10c63 src/admin/web/redirects.js
2e891f34cad2a2950a47e529e15ed9dd41beedec71280b8035b19cfb91a5d317 src/admin/web/settings.js 2e891f34cad2a2950a47e529e15ed9dd41beedec71280b8035b19cfb91a5d317 src/admin/web/settings.js
@@ -291,7 +291,7 @@ d789bf40cf9433e2fd16409d112210fe93154588b1ac9bddc9c7f78e1db14426 src/balance/po
a361c341932ffd186c0b21356c91ab1fe8043f5020d40798266d15ae896a114e src/balance/tests.rs a361c341932ffd186c0b21356c91ab1fe8043f5020d40798266d15ae896a114e src/balance/tests.rs
ae06d238b1451328c751a511476ef39c012f3a397393f939ca02f96ecd0119a6 src/basic_auth/mod.rs ae06d238b1451328c751a511476ef39c012f3a397393f939ca02f96ecd0119a6 src/basic_auth/mod.rs
9a8858b7ff461a4d961ba701ca3ed6eaec15c3f7f05eef8e0e30edc63617605a src/basic_auth/tests.rs 9a8858b7ff461a4d961ba701ca3ed6eaec15c3f7f05eef8e0e30edc63617605a src/basic_auth/tests.rs
e35648537d5ac0bfb604997200d1be25652ee4e8c49bf8b720b68df087bd0249 src/cache/cache_regression_tests.rs 90f26bcd36720076f874cd0a21230316b7303f68e23839e987cf51e13c23352b src/cache/cache_regression_tests.rs
7def03ace07dc38a4806277d75b6ce673d33ddaaf1c4855fa0a3372be1cf9489 src/cache/cold.rs 7def03ace07dc38a4806277d75b6ce673d33ddaaf1c4855fa0a3372be1cf9489 src/cache/cold.rs
b75ff512a1c6344483e00d2c67578ceea6b5472c279da0246f3622daa68d7e16 src/cache/cold/cleanup.rs b75ff512a1c6344483e00d2c67578ceea6b5472c279da0246f3622daa68d7e16 src/cache/cold/cleanup.rs
5fde9e9f77277d557372e4614264512804192bb51f3d2eae785988c17b2e7253 src/cache/cold/cold_tier_tests.rs 5fde9e9f77277d557372e4614264512804192bb51f3d2eae785988c17b2e7253 src/cache/cold/cold_tier_tests.rs
@@ -301,7 +301,7 @@ b75ff512a1c6344483e00d2c67578ceea6b5472c279da0246f3622daa68d7e16 src/cache/cold
c6c54984cf3460e6227d40d8d6917d7ca5d809ac364c80effe354c64133c765d src/cache/collapse.rs c6c54984cf3460e6227d40d8d6917d7ca5d809ac364c80effe354c64133c765d src/cache/collapse.rs
346fdb40d85627b583a01fa17c65e45c822dc7216198cdeadbb3d07904286fa3 src/cache/dashboard.rs 346fdb40d85627b583a01fa17c65e45c822dc7216198cdeadbb3d07904286fa3 src/cache/dashboard.rs
be3d80cd340edb47755190a668e2f2a2776940665f95ae7110893b706eb94faa src/cache/dashboard_tests.rs be3d80cd340edb47755190a668e2f2a2776940665f95ae7110893b706eb94faa src/cache/dashboard_tests.rs
5b0a3dec613fa22a38237618ddaeeca9df5c79acb499bfd78a31d9e7ce104d61 src/cache/fill.rs 847c660e6cb7d752f9dac2807c5045a000172c25b0e437cbade06ad7b101dcba src/cache/fill.rs
675d18afb53f25c56cba49bbb431fa39ecd9d7bdd192c7b39b0698225de7a2a2 src/cache/invalidation.rs 675d18afb53f25c56cba49bbb431fa39ecd9d7bdd192c7b39b0698225de7a2a2 src/cache/invalidation.rs
c1357a13658e1ed5158084d3a41ba9ea906512774a5863ce9c56cb508d3fa6c8 src/cache/invalidation/ban.rs c1357a13658e1ed5158084d3a41ba9ea906512774a5863ce9c56cb508d3fa6c8 src/cache/invalidation/ban.rs
bbd9f372648d89b5e14d5b58029582d37f66a89752caf2c14eb1cbf8f24bb7a0 src/cache/invalidation/http_invalidation_tests.rs bbd9f372648d89b5e14d5b58029582d37f66a89752caf2c14eb1cbf8f24bb7a0 src/cache/invalidation/http_invalidation_tests.rs
+2 -2
View File
@@ -77,10 +77,10 @@ ENV_FILE=integrations/routeros-oci-build/.env \
bash integrations/routeros-oci-build/build-routeros-oci.sh push bash integrations/routeros-oci-build/build-routeros-oci.sh push
``` ```
For example, with RustProxy version `0.35.4` and the defaults this publishes: For example, with RustProxy version `0.35.5` and the defaults this publishes:
```text ```text
zot.example.net/network/rustproxy:0.35.4 zot.example.net/network/rustproxy:0.35.5
zot.example.net/network/rustproxy:latest zot.example.net/network/rustproxy:latest
zot.example.net/network/rustproxy:routeros zot.example.net/network/rustproxy:routeros
``` ```
+2 -2
View File
@@ -2849,12 +2849,12 @@
"appHealthWarning": "Wymaga uwagi", "appHealthWarning": "Wymaga uwagi",
"appHealthError": "Wykryto problem", "appHealthError": "Wykryto problem",
"appHealthSidebarChecking": "SPRAWDZANIE", "appHealthSidebarChecking": "SPRAWDZANIE",
"appHealthSidebarOk": "APLIKACJA OK", "appHealthSidebarOk": "SYSTEM OK",
"appHealthSidebarWarning": "APLIKACJA: UWAGA", "appHealthSidebarWarning": "APLIKACJA: UWAGA",
"appHealthSidebarError": "APLIKACJA: BŁĄD", "appHealthSidebarError": "APLIKACJA: BŁĄD",
"appHealthUpdated": "Aktualizacja: {time}", "appHealthUpdated": "Aktualizacja: {time}",
"appHealthNoStatus": "Brak aktualnego statusu", "appHealthNoStatus": "Brak aktualnego statusu",
"appHealthApi": "API sterujące", "appHealthApi": "API",
"appHealthApiOk": "Status live aplikacji odpowiada.", "appHealthApiOk": "Status live aplikacji odpowiada.",
"appHealthApiError": "Brak aktualnego statusu aplikacji.", "appHealthApiError": "Brak aktualnego statusu aplikacji.",
"appHealthListeners": "Listenery", "appHealthListeners": "Listenery",
+1 -1
View File
@@ -2,7 +2,7 @@
"openapi": "3.0.3", "openapi": "3.0.3",
"info": { "info": {
"title": "RustProxy Administration API", "title": "RustProxy Administration API",
"version": "0.35.4", "version": "0.35.5",
"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." "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": [ "servers": [
+3 -3
View File
@@ -435,8 +435,6 @@ function renderDiagnostics(status, appendSample = true, systemSample = appendSam
$("process-summary").hidden = d.process_threads == null; $("process-summary").hidden = d.process_threads == null;
if (d.process_threads != null) $("process-summary").textContent = `${fmt(d.process_threads)} ${t("threads")}`; if (d.process_threads != null) $("process-summary").textContent = `${fmt(d.process_threads)} ${t("threads")}`;
setOptionalMetric("system-cpu", d.cpu_percent != null, `${fmt(d.cpu_percent, 1)}%`); setOptionalMetric("system-cpu", d.cpu_percent != null, `${fmt(d.cpu_percent, 1)}%`);
const sourceSupported = !!d.source && d.source !== "unsupported";
$("system-source").hidden = !sourceSupported; if (sourceSupported) $("system-source").textContent = t("realSample");
const systemMemory = knownPair(d.memory_used_bytes, d.memory_total_bytes, value => fmtBytes(value)); const systemMemory = knownPair(d.memory_used_bytes, d.memory_total_bytes, value => fmtBytes(value));
setOptionalMetric("system-memory", systemMemory != null, systemMemory); setOptionalMetric("system-memory", systemMemory != null, systemMemory);
const ramMeter = $("memory-meter"), ramFill = $("memory-meter-fill"); const ramMeter = $("memory-meter"), ramFill = $("memory-meter-fill");
@@ -457,7 +455,9 @@ function renderDiagnostics(status, appendSample = true, systemSample = appendSam
setOptionalMetric("system-swap", systemSwap != null, systemSwap); setOptionalMetric("system-swap", systemSwap != null, systemSwap);
const loadSupported = Array.isArray(d.load_average) && d.load_average.length > 0; const loadSupported = Array.isArray(d.load_average) && d.load_average.length > 0;
setOptionalMetric("system-load", loadSupported, loadSupported ? d.load_average.map(n => fmt(n, 2)).join(" / ") : ""); setOptionalMetric("system-load", loadSupported, loadSupported ? d.load_average.map(n => fmt(n, 2)).join(" / ") : "");
setOptionalMetric("system-uptime", d.system_uptime_seconds != null, d.system_uptime_seconds == null ? "" : uptime(d.system_uptime_seconds)); const systemUptime = $("system-uptime"), systemUptimeMeta = systemUptime?.closest(".system-uptime-meta");
if (systemUptimeMeta) systemUptimeMeta.hidden = d.system_uptime_seconds == null;
if (systemUptime && d.system_uptime_seconds != null) systemUptime.textContent = uptime(d.system_uptime_seconds);
} }
$("system-chart").hidden = live.cpu_percent == null; if (appendSample && live.cpu_percent != null) { systemSamples.push(Number(live.cpu_percent)); systemSamples = systemSamples.slice(-window.rustProxyOverviewSamples.getLimit()); } $("system-chart").hidden = live.cpu_percent == null; if (appendSample && live.cpu_percent != null) { systemSamples.push(Number(live.cpu_percent)); systemSamples = systemSamples.slice(-window.rustProxyOverviewSamples.getLimit()); }
$("system-sparkline").setAttribute("points", systemSamples.map((n, i) => `${i * 300 / Math.max(1, systemSamples.length - 1)},${95 - Math.max(0, Math.min(100, n)) * .9}`).join(" ")); $("system-sparkline").setAttribute("points", systemSamples.map((n, i) => `${i * 300 / Math.max(1, systemSamples.length - 1)},${95 - Math.max(0, Math.min(100, n)) * .9}`).join(" "));
+59 -14
View File
@@ -1004,6 +1004,10 @@ html[data-dashboard-density=compact] #panel-overview .stat>span {
line-height: 1.35; line-height: 1.35;
} }
html[data-dashboard-density=compact] #panel-overview .stat-cache-outcomes .cache-mix-header>span {
font-size: 11px;
}
html[data-dashboard-density=compact] #panel-overview .stat strong { html[data-dashboard-density=compact] #panel-overview .stat strong {
font-size: 22px; font-size: 22px;
margin: 3px 0 2px; margin: 3px 0 2px;
@@ -1028,6 +1032,10 @@ html[data-dashboard-density=ultra] #panel-overview .stat>span {
line-height: 1.08; line-height: 1.08;
} }
html[data-dashboard-density=ultra] #panel-overview .stat-cache-outcomes .cache-mix-header>span {
line-height: 1.08;
}
html[data-dashboard-density=ultra] #panel-overview .stat strong { html[data-dashboard-density=ultra] #panel-overview .stat strong {
font-size: 18px; font-size: 18px;
margin: 2px 0 1px; margin: 2px 0 1px;
@@ -2097,7 +2105,12 @@ html[data-dashboard-density] #panel-overview .stat :is(.stat-chart-legend, .over
flex: 1 1 auto; flex: 1 1 auto;
min-width: 0; min-width: 0;
color: var(--muted); color: var(--muted);
font-size: 11px; font-family: var(--sans);
font-size: 12px;
font-weight: 600;
line-height: 1.35;
letter-spacing: normal;
text-transform: none;
} }
#panel-overview .stat-cache-outcomes .cache-mix-caption { #panel-overview .stat-cache-outcomes .cache-mix-caption {
@@ -2132,16 +2145,18 @@ html[data-dashboard-density] #panel-overview .stat :is(.stat-chart-legend, .over
} }
#panel-overview .cache-mix-legend { #panel-overview .cache-mix-legend {
display: grid; display: flex;
grid-template-columns: repeat(2, minmax(0, 1fr)); align-items: center;
gap: 5px 8px; justify-content: space-between;
gap: 7px;
line-height: 1.25; line-height: 1.25;
white-space: nowrap;
} }
#panel-overview .cache-mix-legend>span { #panel-overview .cache-mix-legend>span {
display: flex; display: inline-flex;
align-items: center; align-items: center;
gap: 4px; gap: 3px;
min-width: 0; min-width: 0;
} }
@@ -2164,19 +2179,49 @@ html[data-dashboard-density] #panel-overview .stat :is(.stat-chart-legend, .over
} }
#panel-overview .cache-mix-legend b { #panel-overview .cache-mix-legend b {
display: flex; display: inline-flex;
flex-direction: column; align-items: baseline;
align-items: flex-end; gap: 2px;
margin-left: auto; margin-left: 1px;
color: var(--text); color: var(--text);
font: 500 10px var(--mono); font: 500 9px var(--mono);
overflow-wrap: anywhere;
text-align: right;
} }
#panel-overview .cache-mix-legend .cache-mix-percent { #panel-overview .cache-mix-legend .cache-mix-percent {
color: var(--muted); color: var(--muted);
font: 400 10px var(--mono); font: 400 8px var(--mono);
}
#panel-overview .cache-mix-legend .cache-mix-percent::before {
content: "· ";
}
#panel-overview .system-card .system-uptime-meta,
#panel-overview .connection-card .connection-backends-meta {
white-space: nowrap;
}
#panel-overview .system-card .system-uptime-meta b,
#panel-overview .connection-card .connection-backends-meta b {
color: var(--text);
font-weight: 650;
}
#panel-overview .connection-card .connection-heading-main {
width: 100%;
min-width: 0;
}
#panel-overview .connection-card .connection-current-main {
display: inline-flex;
align-items: baseline;
gap: 6px;
min-width: 0;
}
#panel-overview .connection-card .connection-backends-meta {
margin-left: auto;
line-height: inherit;
} }
/* Live values stay on one line so refreshes do not change card heights. */ /* Live values stay on one line so refreshes do not change card heights. */
+7 -7
View File
@@ -334,7 +334,8 @@
<div> <div>
<h3 class="overview-chart-heading" data-i18n="systemLoad">System load</h3> <h3 class="overview-chart-heading" data-i18n="systemLoad">System load</h3>
<h2><span id="system-cpu">-</span> <small>CPU</small></h2> <h2><span id="system-cpu">-</span> <small>CPU</small></h2>
</div><span class="meta" id="system-source">-</span> </div><span class="meta system-uptime-meta"><span data-i18n="systemUptime">System uptime</span>: <b
id="system-uptime">-</b></span>
</div><svg preserveAspectRatio="none" aria-label="System CPU history" data-i18n-aria="systemChart" id="system-chart" </div><svg preserveAspectRatio="none" aria-label="System CPU history" data-i18n-aria="systemChart" id="system-chart"
role="img" viewbox="0 0 300 100"> role="img" viewbox="0 0 300 100">
<path class="chart-grid" d="M0 25H300 M0 50H300 M0 75H300"></path> <path class="chart-grid" d="M0 25H300 M0 50H300 M0 75H300"></path>
@@ -348,14 +349,15 @@
<div class="memory-line"><span data-i18n="systemSwap">System swap</span><b id="system-swap">-</b></div> <div class="memory-line"><span data-i18n="systemSwap">System swap</span><b id="system-swap">-</b></div>
<div class="chart-footer"><span data-i18n="loadAverage">Load 1 / 5 / 15 min</span><span id="system-load">-</span> <div class="chart-footer"><span data-i18n="loadAverage">Load 1 / 5 / 15 min</span><span id="system-load">-</span>
</div> </div>
<div class="chart-footer"><span data-i18n="systemUptime">System uptime</span><span id="system-uptime">-</span></div>
</article> </article>
<article class="card connection-card" data-dashboard-widget="connection_chart"> <article class="card connection-card" data-dashboard-widget="connection_chart">
<div class="card-heading"> <div class="card-heading">
<div> <div class="connection-heading-main">
<h3 class="overview-chart-heading" data-i18n="connectionActivity">Connection activity</h3> <h3 class="overview-chart-heading" data-i18n="connectionActivity">Connection activity</h3>
<h2><span id="connection-current">0</span> <small data-i18n="connections">Open <h2><span class="connection-current-main"><span id="connection-current">0</span> <small
connections</small></h2> data-i18n="connections">Open connections</small></span><small
class="meta connection-backends-meta"><span data-i18n="backends">Backends</span>: <b
id="connection-backends">0</b></small></h2>
</div> </div>
</div> </div>
<svg preserveAspectRatio="none" aria-label="Connection activity history" data-i18n-aria="connectionActivity" <svg preserveAspectRatio="none" aria-label="Connection activity history" data-i18n-aria="connectionActivity"
@@ -368,6 +370,4 @@
connections</span> <b id="connection-open-value">0</b></span><span connections</span> <b id="connection-open-value">0</b></span><span
class="connection-exchange-key"><i></i><span data-i18n="activeExchanges">Active class="connection-exchange-key"><i></i><span data-i18n="activeExchanges">Active
exchanges</span> <b id="connection-exchange-value">0</b></span></div> exchanges</span> <b id="connection-exchange-value">0</b></span></div>
<div class="chart-footer"><span><span data-i18n="backends">Backends</span>: <b id="connection-backends">0</b></span>
</div>
</article> </article>
@@ -517,5 +517,4 @@
<path class="chart-grid" d="M0 15H300 M0 30H300 M0 45H300"></path> <path class="chart-grid" d="M0 15H300 M0 30H300 M0 45H300"></path>
<polyline class="diagnostic-line proto-h2-line" id="www_php_requests-line" points="0,55 300,55"></polyline> <polyline class="diagnostic-line proto-h2-line" id="www_php_requests-line" points="0,55 300,55"></polyline>
</svg> </svg>
<small data-i18n="webMetricPerSecond">Requests per second</small>
</article> </article>
+39 -2
View File
@@ -6,7 +6,6 @@ mod tests {
h.insert("cache-control", value.parse().unwrap()); h.insert("cache-control", value.parse().unwrap());
h h
} }
// Legacy policy; varnish-compatible behavior is tested separately.
fn settings() -> Settings { fn settings() -> Settings {
Settings { Settings {
enabled: true, enabled: true,
@@ -1559,7 +1558,10 @@ mod tests {
let second = cache let second = cache
.ticket(1, "http", "example.test", "app", "/second", &headers) .ticket(1, "http", "example.test", "app", "/second", &headers)
.unwrap(); .unwrap();
fill(&cache, first.clone(), "first", &s).await; // Stored bodies are trimmed to their real size, so the first object must
// itself be large for the next fill reservation to need its space.
let large: &'static str = Box::leak("f".repeat(60 * 1024).into_boxed_str());
fill(&cache, first.clone(), large, &s).await;
assert!(cache.get(&first).is_some()); assert!(cache.get(&first).is_some());
let before = cache.view(); let before = cache.view();
assert!(before.hot_allocated_bytes <= s.max_bytes); assert!(before.hot_allocated_bytes <= s.max_bytes);
@@ -1821,4 +1823,39 @@ mod tests {
assert_eq!(cache.view().entries, 0); assert_eq!(cache.view().entries, 0);
assert_eq!(cache.view().fills_active, 0); assert_eq!(cache.view().fills_active, 0);
} }
#[tokio::test]
async fn stored_entries_do_not_pin_origin_buffers_or_spare_capacity() {
let cache = Cache::new(1);
let s = settings();
let t = ticket(&cache, &HeaderMap::new());
// Header values parsed by hyper are slices of a larger read buffer.
let read_buffer = Bytes::from(vec![b'x'; 64 * 1024]);
let mut h = headers("max-age=60");
h.insert(
"x-origin",
HeaderValue::from_maybe_shared(read_buffer.slice(0..16)).unwrap(),
);
h.insert(
::http::header::ETAG,
HeaderValue::from_maybe_shared(read_buffer.slice(16..24)).unwrap(),
);
let p = plan(StatusCode::OK, &h, &s, Duration::ZERO).unwrap();
let mut response = Response::new(Body::from("small body"));
*response.headers_mut() = h;
cache
.wrap(response, t.clone(), p, &s)
.into_body()
.collect()
.await
.unwrap();
assert!(cache.get(&t).is_some());
assert!(
read_buffer.try_into_mut().is_ok(),
"cached headers must not keep the origin read buffer alive"
);
let store = cache.store.lock().unwrap();
let entry = store.entries.values().next().expect("stored object");
assert_eq!(entry.body.len(), 10);
assert!(entry.body_allocated <= 10 + 10 / 8 + 1);
}
} }
+40 -2
View File
@@ -1,3 +1,16 @@
fn detached_header_value(value: &HeaderValue) -> HeaderValue {
let mut detached = HeaderValue::from_bytes(value.as_bytes())
.expect("existing HTTP header value must remain valid when copied");
detached.set_sensitive(value.is_sensitive());
detached
}
fn detach_header_map(headers: &mut HeaderMap) {
for value in headers.values_mut() {
*value = detached_header_value(value);
}
}
struct ByteGaugeGuard<'a> { struct ByteGaugeGuard<'a> {
counter: &'a AtomicU64, counter: &'a AtomicU64,
bytes: u64, bytes: u64,
@@ -102,6 +115,9 @@ impl Candidate {
let (body, body_allocation) = if let Some(body) = self.shared.take() { let (body, body_allocation) = if let Some(body) = self.shared.take() {
(body, self.shared_allocated) (body, self.shared_allocated)
} else { } else {
if self.data.capacity() > self.data.len().saturating_add(self.data.len() / 8) {
self.data.shrink_to_fit();
}
let allocated = self.data.capacity().max(self.data.len()); let allocated = self.data.capacity().max(self.data.len());
(Bytes::from(std::mem::take(&mut self.data)), allocated) (Bytes::from(std::mem::take(&mut self.data)), allocated)
}; };
@@ -111,6 +127,12 @@ impl Candidate {
let domain = self.ticket.domain.clone(); let domain = self.ticket.domain.clone();
let path = self.ticket.path.clone(); let path = self.ticket.path.clone();
let target = self.ticket.target.clone(); let target = self.ticket.target.clone();
detach_header_map(&mut self.headers);
self.origin_etag = self.origin_etag.as_ref().map(detached_header_value);
self.origin_last_modified = self
.origin_last_modified
.as_ref()
.map(detached_header_value);
let tags = cache_tags(&self.headers); let tags = cache_tags(&self.headers);
let cost = hot_entry_cost( let cost = hot_entry_cost(
body_allocation, body_allocation,
@@ -226,7 +248,21 @@ impl HttpBody for FillBody {
let needed = candidate.data.len().saturating_add(data.len()); let needed = candidate.data.len().saturating_add(data.len());
if needed <= candidate.settings.max_object_bytes { if needed <= candidate.settings.max_object_bytes {
let before = candidate.data.capacity(); let before = candidate.data.capacity();
let required_growth = needed.saturating_sub(before); let target_capacity = if needed <= before {
before
} else if let Some(length) =
candidate.plan.expected_length.filter(|length| {
*length >= needed
&& *length <= candidate.settings.max_object_bytes
})
{
length
} else {
needed
.max(before.saturating_mul(2))
.min(candidate.settings.max_object_bytes)
};
let required_growth = target_capacity.saturating_sub(before);
if required_growth > 0 if required_growth > 0
&& !candidate && !candidate
.fill_gauge .fill_gauge
@@ -246,7 +282,9 @@ impl HttpBody for FillBody {
} else if required_growth > 0 } else if required_growth > 0
&& candidate && candidate
.data .data
.try_reserve_exact(needed.saturating_sub(candidate.data.len())) .try_reserve_exact(
target_capacity.saturating_sub(candidate.data.len()),
)
.is_err() .is_err()
{ {
candidate.cache.record_reason( candidate.cache.record_reason(