diff --git a/CHANGELOG.md b/CHANGELOG.md index c86aba5..9aa7271 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ ## 0.34.0 +- Cache regression fix: interpret local max TTL as a cap on remaining freshness at receipt, not on the upstream Age clock. Preserve RFC 9111 Age and transformed response validators; prohibit private/no-store caching. +- HOT hit optimization: update LRU and hit counts in place, without removing/re-indexing the complete cache entry and its Vary variants on every hit. +- Expose both total HTTP Age and time resident in RustProxy HOT/COLD in the cache dashboard, with Polish/English labels. +- Add 100,000-case deterministic freshness simulation, executable loopback HTTP regression (including Brotli), and Rust HOT/COLD age/transform/persistence tests. Production compilation and post-change RPS measurement are still required. + + - Optimize reverse-proxy hot path with shared immutable compiled route handles, reusing the observer's host/location selection in forwarding without changing ACL, rate, canonical authority or protocol enforcement. diff --git a/SHA256SUMS b/SHA256SUMS index 5affa5e..10fd6a9 100644 --- a/SHA256SUMS +++ b/SHA256SUMS @@ -2,7 +2,7 @@ 4140a2956264b44f259e6a37fc00ba02097bbe68b09296e04d3d243c1287129b .env.example 9e6356475bf587091bab72246ec9e325b498f7e48a6220e9a18baa50d0a385a6 .gitignore 46bab1d2c2d6e0a80d57a6b232b1ba4c220884b95cd45ddccbafce2aa160cddb AGENTS.md -37ed26e41820a69fe6417e7600c9ec5a2eeab69fd11e5a389be912a2a3cd7642 CHANGELOG.md +4e0a7371f060063a6a73ae1c1a2faba2de8d227118be2406c88ca432c90305eb CHANGELOG.md ca201e3cd3f9842eae0006d0b40a0a72bcd3d4da6e4e5ecaf200d1b9a1390db2 Cargo.lock fec5f1bae9a59ef1fabd27c5e45d31448dd8f811736eebfa8826b3806a7e3349 Cargo.toml 25c7f3c8162cbf5cc156439774118a81dae9fdc52b611ec7e40c230fc99a772c Dockerfile @@ -59,6 +59,7 @@ deea89aed410c0619bdbdb12437edc7aff9dca2fec7fdc059e918c649fc36b51 docs/PROXY_HOT 887d1fdcc3b546b024afcd18b1716b8e3a74a3800012bf4bda7a122d2eabe233 docs/README.md 6e46a137b9c88dac8cb9e3fdca877430092392de9913d746278dbff8652460c2 docs/REDIRECTS.md 0dfd0d431c5aedc67abac1ce5de040ffa790ec9578fd7d6f91a987c333d73358 docs/REFERENCES.md +540fa46716d562bfc846d2f7bac0515380831ddbdcaa01ff4ac86be4ff3d3aa0 docs/RELEASE_0.34.0_CACHE_FIX_PL.md d85c5567fc6a7714b96ad7cfe4ee9ff2085f84c4f31534a6484340d03a73e0f7 docs/RENEWAL.md cd4ed3af26eb51c9ff6ef3dda9d52ff5120bcfc78c842bce34a639cf85b6aea9 docs/ROADMAP_HISTORY.md 759bf2987f2b602488829d1856fa33d57c2a3b23bc681ef5a931b9633af3a533 docs/SECRET_STORE_BACKUP.md @@ -100,8 +101,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 -462339bc35535fa69ebd95aaf43e9405913d940406bfa14b27d15afb62accef5 langs/en_US.json -22efd93e26f71bd78c1e6cf83a9f0aaab3a8a5a4adb98822cbf73ba6e22cb991 langs/pl_pl.json +315f673be9a929069f6ad0c60a215d30d7c3dc2de4105e208810c371c488b268 langs/en_US.json +ca68b7475d3b744b3cd091140ef1d5aaa6f7fa880832498ff9aee7b0ee252846 langs/pl_pl.json a99ad040be10fa028351e290b9363236b3513a1cadbdc9fb9e0260d517b9b0ae make_zip.py e830d37dd1f81a4b0aa7d535f5bba69e34e433b0fd99cc8ee0b296786c32379a migrations/0002_admin.sql 20112cc82192098b8d602f1c4f7ca08712e9e1366c845fabb92753187c370d35 migrations/0003_certificate_renewals.sql @@ -155,6 +156,8 @@ e69813fb1d3a4cdcfb7243964cc323fc21a603087bf2e84188fa42b9d3cee4b5 scripts/runtim 174c8059625e3315a3d9fefe74c17f78ed850ff25ee15bfdabc148107dd344eb scripts/start_stream_backends.sh 046b4282550f5cb4e53906665c91c7442be70fc68fd0743466fd832582f7c979 scripts/test_stream_tcp.py f0b48ec0cc4411755cc0b4128eebce710375afa99344cb76198cf31074f8eb63 scripts/test_stream_udp.py +fafd577ccbb58485c47de35fc125e5c64a3a7628ae40d01d4cd924fce2f414db scripts/tests/cache_age_policy_034_model.py +972d79127309071a15e231ca45d24c9a8347c25115d0ec4fd91a74ca56b3f665 scripts/tests/cache_age_transform_034_live.py 955c150f8d0490069cb14b659d4fb4e0b529a28b87c27bd6697935c23e7ef192 scripts/tests/cache_scope_034_static_test.py efb7a1fde2c74f30cd4a1abb88ae07c1cac7378bb33685dd09d52bb30849daac scripts/tests/dashboard_chart_headers_0335_browser_test.py eb2c9e5c968938b6fbe4675b547ba1f537519878b9095e1fea133f4d83f96fc8 scripts/tests/dashboard_chart_typography_0337_browser_test.py @@ -188,26 +191,26 @@ f0a2e3daa0a49aac54723cb5a281360e49a97c076281372c5cca2a85e096c02c scripts/tests/ f55efa99245bbdbc98fe3202e52952d224ac3200612561580d52f6e251810049 scripts/tests/web_server_0330_ui_test.py 0dd1cef06a1c3e1546e2fb9b085bf369dfbed02107b9ab01b4fb4f3b894099c0 scripts/tests/web_server_0334_browser_test.py 22e880e98c7b9d700c7a4c02b9b1d543e5dbd1f4ecdca42813a1083165b32a19 scripts/version.py -4803e44de39b872a5b3b55f9ca9e81c066ba52cb8f6adb879fd57c5f94b93e89 src/acl/dynamic/tests.rs -63efab1e95d41134fc30cc57320c32810bbae9f81a640bdb24b1be2059e63d8a src/acl/dynamic.rs -a22e5ea6381a1eacafe650be0f5cd6e653773e31f6491a562fe0459a309fb7cc src/acl/tests.rs 55485a513e8c4da2a58daa7abcb15b32ed408a5fc062cf23599fb83d16b90cfe src/acl.rs +63efab1e95d41134fc30cc57320c32810bbae9f81a640bdb24b1be2059e63d8a src/acl/dynamic.rs +4803e44de39b872a5b3b55f9ca9e81c066ba52cb8f6adb879fd57c5f94b93e89 src/acl/dynamic/tests.rs +a22e5ea6381a1eacafe650be0f5cd6e653773e31f6491a562fe0459a309fb7cc src/acl/tests.rs +6f5d3137bf24451da05c1db9f0f9e2a451305db17b6bc2590815ad54a6511829 src/acme.rs 587097620b2f25ce7c6f59f907b47660184b095e3040c7615e74509a82e7cdd8 src/acme/jobs.rs 3f158f46e80b403b658b4e9b1e3710e38c70e47b2d476b8223d9c394ffeeba95 src/acme/model.rs -d1dcb7bdfb7cfdc9c3b88cfb6908201c58532bc888744a13f45853079f214659 src/acme/providers/tests.rs c5334de6c732d76b2bea7bfc17b3ac305a250bbaad31a5420d6a7d7abb200449 src/acme/providers.rs +d1dcb7bdfb7cfdc9c3b88cfb6908201c58532bc888744a13f45853079f214659 src/acme/providers/tests.rs 29ff0647417b0f1d50a4cc075ab51afecff9ddf47db3eb7948d51db5a38f33f3 src/acme/runtime_bootstrap.rs 87f64198770ae026c03a242fa542db2590ca734b02e756f1e5c28d66236f753a src/acme/runtime_env.rs f8075a5ef9ae5651d72a33ac0f0fd5b44ad0ae30f6e2d2318412177e0ed837f5 src/acme/runtime_versions.rs e38331a1b186b49fe9d04051de52b603e1fa028def37e4e2f52e386b4d7b29ac src/acme/tests.rs -6f5d3137bf24451da05c1db9f0f9e2a451305db17b6bc2590815ad54a6511829 src/acme.rs b6f38f3fd75d6685bbc882ed1077a38bf495cfcf01c397f69ed9b98be68b446f src/admin/access.rs b4a2a068acfa1143b0032b9cd072c19cf3fdda2580f0b932d11d6368cd2ab3ad src/admin/certificate_api.rs 51f46a2cb3167c4e3a784dfbb59b8fe0e9d5d3d51365b26699498e31d0afb6a9 src/admin/certificates.rs b5f6d49f1add583cfc8cd4aa36ffe4db56dac4de3b151fe8239fe42f507019cc src/admin/dashboard_presets.rs +5e150d4ef0413a2f92db5b6631669933b84d4b4796633d01476c4b39188cd05c src/admin/documentation.rs 958546c43c05bf4bed8121b24db3b3096f9243f3c56a71e1762592b755684013 src/admin/documentation/documents.rs 67b901485d5858d5b5bf78a6260035db32241531d99481754c3533fdf404facb src/admin/documentation/tests.rs -5e150d4ef0413a2f92db5b6631669933b84d4b4796633d01476c4b39188cd05c src/admin/documentation.rs 1ce779b84aa8f47bdb3c34f83593c1f2f06d2235f0319847096cfcd035434168 src/admin/file_log_search.rs ab18acf6fb4ac86fb22635b9219a12dac76d24952c8f15538486267a9b4b7855 src/admin/file_logs.rs c6b552cd5acd9e743c28b1a5564420c214c619fe891ab0561b7d4499aae8d6c0 src/admin/file_logs_io.rs @@ -221,8 +224,8 @@ d9120f7dc61d27621c5ac27ea49815dc7945c44d5b99d208da503818c198f649 src/admin/oper 92b3e05f04711d8001b56816405859631d9e917868e15be965c7e76ef4ddef99 src/admin/preferences.rs 4a5cb4c3a3aa8b9a519020854506ce4be5e688a6c4298260322ae641dded7fe9 src/admin/preferences_columns.rs 9a3f13e2477769ae680c03d63336880c3b7b7d5aba4a91e44390a976608b9b1d src/admin/preferences_tests.rs -7a00e4ab943f74d2b1bdcbfab7f9cd3f584e9f59536b4aca6c4c31f5f5508d12 src/admin/public/tests.rs 4a7a2017ba57c9e7a8b29e73764d439f6d03653403909ef198ded8c48d152784 src/admin/public.rs +7a00e4ab943f74d2b1bdcbfab7f9cd3f584e9f59536b4aca6c4c31f5f5508d12 src/admin/public/tests.rs 9926827131254677a848c178c80850b3ca1993c05b4bf913687dc0c7992ad048 src/admin/refresh_preferences.rs daef5e663c1bc99a22b3b8fa4481ae5e4916b91db132c104bc050f51b1fdf77f src/admin/router.rs a40adfbaa908da3ea726d7aa3d45394a70a6a55b6fc0063270ec4d2a2f2026a3 src/admin/session.rs @@ -251,7 +254,7 @@ daa20d634f921191cb4ac37889504f203ab39ad7e8fd8f33e1b182fc4206c24d src/admin/web/ 86ac42bd4a6a84bb137d5a3c3dc3d1f4e404a543447845e6ea6e6e8210e268ce src/admin/web/app/settings.js 8386710827e5ccc9432fb46413368f94afc1016425404a6092b460903636837e src/admin/web/app/stream-dashboard.js 7f89bfae66e2a08a05a112733864e908f036bb1ee3d8b5b9ff23783b870acd96 src/admin/web/app/web-overview.js -bb94697a1cbeccaf80069dd47ab84efe14b052d81c472f8309478bbeb4e05f06 src/admin/web/cache-panel.js +849b2ca9d183bdf6cb1e04651cda52da55b8a631e11ab1d827a052c8436bbd76 src/admin/web/cache-panel.js 02a9f5a61379e68e1723e64ef4c589500e9a993adcb02fe352f1cf9456c90c52 src/admin/web/certificate-api.js aec5755244242424e5091ff57c0258d2618588618fe1d52d36f081d03879f686 src/admin/web/dashboard-defaults.json 797e2935a34b974cb0e07a88056c31e6948cc11385bf2a076d902a332882d0a0 src/admin/web/dashboard-widgets.json @@ -276,7 +279,7 @@ e6c4d91d1542d0a5b47bb8736f9539d43a6713df5a473b635519d5b7eac2eb9c src/admin/web/ 0a5fff35555153f59d4346933030a67b6e1a8768cee7a47cfa2fcf1a2c564f63 src/admin/web/favicon.svg 7cbdef9192a9dee1f8eac42b85f52b3190f7f6efae50004aa7ad116a910e4036 src/admin/web/file-logs.js b14e7b3578322f309627f6fe965cc16abcf85da3437c9070be6caecae1908743 src/admin/web/host404.js -7ffdda1b657c613f2bd3b7a9c7721d67d3d7a159351aaeccbde2a213597b77f7 src/admin/web/index.html +ab762658c3f668a2890d275a869cecb7255352bbd97c8b6b619572627f3196f9 src/admin/web/index.html 03ad9572bb14c34059636d612cf6b876d6361ce601817cff674c57b715dc65dd src/admin/web/integrations.js 7a12f020fc587205694978ab41b660e9a80487d413fbf6e34fc525eabc58308f src/admin/web/login-keys.json cbd41678eadd994dc5252628ee8ef9551fa9f7d8694ca5abd206240d9a96ad30 src/admin/web/login.html @@ -299,17 +302,18 @@ b3239e67901f1796d7a974ade0796f2e3590ff8064628a5629b78c7f6ce2f32e src/admin/web/ bb93e2017f40e3a45ff7f4ca92e4188bb464f432704b6d2c39da9d9621b7984c src/admin/web/vhosts/render.js 4dfdeb7c73c2775eacaca65fd8ef1dc80b275421b15522d319d338f5b96288cc src/admin/web/web-server-profiles.js fd476445a88eb40270e706814eee50cbfbba4069a26dd843c095367e55a147a1 src/admin/web/web-server.js -b2f948bcc3dbd24952c7b1b02d41d06757f49f0c38a78caf51f8f8a687d8480d src/auth/files/tests.rs 53237ae8b08d261ce21e0aa6fd225bf4f3bb17a37a80529e2a4039d45b13f7c5 src/auth/files.rs +b2f948bcc3dbd24952c7b1b02d41d06757f49f0c38a78caf51f8f8a687d8480d src/auth/files/tests.rs 775178ee5781e64574bdd7c1fb7d64e7e283977fbd9c98c99896532a7f1df612 src/auth/mod.rs c96a87e82ff0c1c9ce3d0cd5135903bb53af78d1c4fb6ebfe5fea503bf5644ea src/auth/store.rs 745226cabb007819370fc6aa680995a03a8a13fa057dacfab0fcc21d0c43bbe4 src/auth/tests.rs +09c3a622a7d2169e49e3369ea5f0f816eab2f717eaf1675c625d518c8f34d367 src/backup.rs 76aa2afe9e7302be39b3512f30d0448d9134300f8ae930d64ada40cf3ad4a8a3 src/backup/archive.rs 732cd4f9ed38ae69f8bbae61b1db8baaa6f86b07ca21c41f24a206a30f0a96fc src/backup/ownership.rs 076350506215faec3cfe7d9de4e60baf29672cc22a41eabe601dcc510c257799 src/backup/snapshot.rs 5c19490d834d9971166b6b784a75b081bb95fd50c8c634ef3c87924dfffd4a19 src/backup/tests.rs f5afae218f3a6f91bc2f1f5a90094630ce5b7ca574de61807b5a317b13937ec2 src/backup/validation.rs -09c3a622a7d2169e49e3369ea5f0f816eab2f717eaf1675c625d518c8f34d367 src/backup.rs +426a946b2c9e244f09f6cbc5f9664b8ad0737529a9bb5a3d549d27196a1f8043 src/balance.rs ca1e03b56a872dca37ed9d05ead41c1538a808e80b09fb9494823c443cd51c61 src/balance/health.rs 59d90e709bfc2be6cd48576f1c1d222891523853a46f2561f0562d74d01f60a5 src/balance/lease_runtime.rs 554b730c39a935b7da46bfb76b474b99cee07f8c482cb0490f2cf81ba7a51cf2 src/balance/model.rs @@ -317,48 +321,48 @@ ca1e03b56a872dca37ed9d05ead41c1538a808e80b09fb9494823c443cd51c61 src/balance/he 477132dd381e23f1be197c32ff58a0925f41d3e6aa63fe77c10973cefb2b76f6 src/balance/pool_selection.rs 8abb6048303ee8c022546a528d5693167766e7450efd8e20f37ec6fd0fa9ef5e src/balance/pool_view.rs 842318f21a919055522f8bd9dae67bf4ec1c8c32dc52314cc048ba1d54a0b379 src/balance/tests.rs -426a946b2c9e244f09f6cbc5f9664b8ad0737529a9bb5a3d549d27196a1f8043 src/balance.rs -9a8858b7ff461a4d961ba701ca3ed6eaec15c3f7f05eef8e0e30edc63617605a src/basic_auth/tests.rs 5049d2bd01a9c866f3bad2288d8d594df96bba6045dfe15cd22b4173562b7388 src/basic_auth.rs +9a8858b7ff461a4d961ba701ca3ed6eaec15c3f7f05eef8e0e30edc63617605a src/basic_auth/tests.rs +7def03ace07dc38a4806277d75b6ce673d33ddaaf1c4855fa0a3372be1cf9489 src/cache/cold.rs a9eeb93519aae2de7a1282296ced91d2eb8307cc966f8fbf6085af0fd21b0ad2 src/cache/cold/cleanup.rs 8354ae90c1a0857773a0c6d79427925e0115d94ccfafb809ccc1ebf4ef10f9b9 src/cache/cold/demotion.rs 2eaba3261da2a547e9af91330319a3abd3a8ad8b5b44a337a84040720209017d src/cache/cold/startup.rs e7c7fd71727d542c2df3e03a4a1cba9d839c516963f66bbfde1c29ec81053500 src/cache/cold/worker.rs -7def03ace07dc38a4806277d75b6ce673d33ddaaf1c4855fa0a3372be1cf9489 src/cache/cold.rs d51fa4f320be56c572f767617428c3f3838543cb0eeb7d1f8ae791e1a1ce9a71 src/cache/collapse.rs -284f1cc56113fbcc3b1e617103d75a7b70fd7d43e536d6017c15912154921424 src/cache/dashboard.rs +7e8741bc21e5ca75f3bf8c5e57c59b6814dc1e5e2e0548963fe35089256772bb src/cache/dashboard.rs 780c2654c67dbe176d8310678e6deec8022bcebfd85b95df7262069ed41f57b1 src/cache/fill.rs +675d18afb53f25c56cba49bbb431fa39ecd9d7bdd192c7b39b0698225de7a2a2 src/cache/invalidation.rs c1357a13658e1ed5158084d3a41ba9ea906512774a5863ce9c56cb508d3fa6c8 src/cache/invalidation/ban.rs 0cc31d8e70fb3774c4ce3713b94ed79c184a8d8f0d38ce66a97724410733e17e src/cache/invalidation/invalidate.rs -675d18afb53f25c56cba49bbb431fa39ecd9d7bdd192c7b39b0698225de7a2a2 src/cache/invalidation.rs 373031e18d0c23d006a31822ef977015c0263637e3da70c1442407f7bfed1033 src/cache/lifecycle.rs -88f6210c03d7a8e7a35be1f123c9c15675af6e6a599c50db927d99866851b634 src/cache/lookup/hot.rs +bd831807ca4720b3a41a6ea1d9a6c0ed2d935225e2dacbd9313be064f2e4a20e src/cache/lookup.rs +5aa0d9ae53f0350f5cfc4d1694a6faf9eea893460d421344d3bc5d1c4ce66529 src/cache/lookup/hot.rs 1779abcee77600c13050a2882f896a5b35625b1ae53737c2554179492ce0e40d src/cache/lookup/insert.rs 107a589974b9689009a9bbf088818dfaec71cd1aab8676bbc6d0118359a54a31 src/cache/lookup/tiered.rs -bd831807ca4720b3a41a6ea1d9a6c0ed2d935225e2dacbd9313be064f2e4a20e src/cache/lookup.rs 58c03fde09e5eab40968679793b364f4f1cf5fd832bd79ebcdc92bb23871ad82 src/cache/mod.rs -a7b6dfeb63510e4710eb11a4939b360b8863a4b3f71de263d8f3e50dfd006c57 src/cache/model/cache.rs +0c8b0d550e94d4474dcdf991aa0340228dc5f2f904f39350e6e666a16f16fe87 src/cache/model.rs +875116e319c5bb9d281817fed626a94e468e9e3305f21dac99d3f2535e2fb157 src/cache/model/cache.rs 0ec4f6d0adea1ed80a3ca17c68c9c85502491da2904d9d690b4169ab9b025b21 src/cache/model/cold_metadata.rs 29bfce96b2ffd102d9c848c7b717a45fedb9aa44511f62f7a1f28a53dafd063a src/cache/model/entry.rs 88d74fc1b7b9ca15a54a8f4893ad3993105952148bcfee099e9bc9727b622aa3 src/cache/model/http_invalidation.rs d890524999dc50aeb1dbda90264b46a1d53f08ac923d831b89ba82e4a564d923 src/cache/model/maintenance.rs 5441fa3a384add28b6fdd15300cf2648f8237dbfc211cad9117754203be76911 src/cache/model/settings.rs 55dcc0ad84d6b73689ba43e759d5685c406419c7733e23e78d5b072891ab17d7 src/cache/model/views.rs -0c8b0d550e94d4474dcdf991aa0340228dc5f2f904f39350e6e666a16f16fe87 src/cache/model.rs -989df11e246123f760ef31689370f3500e0913fcc6b70d7ac0c2c95e2f412fb0 src/cache/policy/request.rs -d426d341a7678f8ec70406d86052c97d0f49804bbcd8402951103d61a735b9da src/cache/policy/response.rs e26dce02df9c043329ca164fed215d271781bce8fb03240f528331bf3df6b9d7 src/cache/policy.rs +989df11e246123f760ef31689370f3500e0913fcc6b70d7ac0c2c95e2f412fb0 src/cache/policy/request.rs +d6051d55168fe1db97980a54c22c708f4f325ba72bfc36f35a1851eb5dcc051d src/cache/policy/response.rs 7e2bcfbb2b57732cdc704d9df7a9298fb80e735e37984431bc936630e41e7f8a src/cache/range.rs -291d0dcc3a07926eadbc9419b8fc1740b4023ef01c0521269ae2d83f4a5acb6d src/cache/tests/cold_tier_tests.rs +7ad96b3baae36ec49c90d03b380e749944fb3d54abb045c90db3a35f6b89b1c1 src/cache/tests.rs +9183fa8e6086e92fb148fc278fd866d44e3dd988c848a071e32066e44a1cbf0a src/cache/tests/cold_tier_tests.rs 3842cdcf7c3414b9c30f5fbed927b93e835eec3ef96d4c6ee44250038b834276 src/cache/tests/dashboard_tests.rs d7a02eb7bad37e6a5524600aabb5e60ccf50e26c7a487e2806891c9d8acd48f3 src/cache/tests/http_invalidation_tests.rs 1659ffd8d227d2ec8b98e6a5e06b6143e6ac4ac06ab423c184980abcb47085da src/cache/tests/scope_tests.rs -ddbcf27a667d779065d7a654d8094910e92958d2b8862a2ec2a85ca41b7f21e5 src/cache/tests/tests.rs +d4429cf4f35fd8d0082108fb62602fde72c9c2fc6edfadfe3268c6a8214a8f89 src/cache/tests/tests.rs af28534625859ff66011e10c54cff8f82c2cfa1c173c4d99b89c27c1437f0659 src/cache/tests/v022_cache_tests.rs -7ad96b3baae36ec49c90d03b380e749944fb3d54abb045c90db3a35f6b89b1c1 src/cache/tests.rs 22f8f16cf7383c579b19810819030072fc827681478e17068dddc85da8dc53ad src/cache/tickets.rs -4bdbde197d135fee8be20e93427eba8ca7b60b801717ed7ca734319bedb6ef05 src/compression/tests.rs e0146bf5d2e2e33aedcccd9205e5bd457559c9d77dc7ce266f8c165d1b867f0f src/compression.rs +4bdbde197d135fee8be20e93427eba8ca7b60b801717ed7ca734319bedb6ef05 src/compression/tests.rs +7bc8285cb2012506fd1a38a71dffa561f885f4ab65a9b2a7c8344319e3cd1cf6 src/config.rs dbd57ef3307b937614cdfdb6c1df82acb80cbbef39f09d19fe2edfc24334aa58 src/config/backend.rs beb831a208c4e5f7ebe8327686b1e0edc66608c7032f895cb4fc3366b189aae0 src/config/compile.rs dfa89a9e214d0b33b4efce8fa678f1fec17d17656e203acf84dfd09ce33868e0 src/config/internal_routing.rs @@ -366,58 +370,58 @@ dfa89a9e214d0b33b4efce8fa678f1fec17d17656e203acf84dfd09ce33868e0 src/config/int fc993c356386a9ff17379d48a70ef388df5b2b10ca9ee04f06342f68f9dbbaae src/config/routing.rs a7ccffdeeb258adae41c616022ed0181cf590d708d305d48c63317e4a3f68699 src/config/snapshot.rs 41a4fa4f9a919a8c848ee01d01423d82a136790c9d74f27319c1e5a6d9f18097 src/config/tests.rs -7bc8285cb2012506fd1a38a71dffa561f885f4ab65a9b2a7c8344319e3cd1cf6 src/config.rs +23541660151d9005555a07db6d491455d61b185f0cc70c3ec3a0bee2aef08dc3 src/db.rs 30f0b7269224a64e3f1ec9e6fbe9e27ddb1d308dc84cc9882e50545cf612695d src/db/certificate_api.rs 20ba52d3755c359d670968efa53b0604ff7cbed63a416f9f765b50a1f45074ac src/db/dashboard_presets.rs 2ff744223934685439374572b83fd639bb3eabdbac168bea4a6501a6e9ce0ee0 src/db/history.rs c05a02618d476e4670b4f9930555f199cac776cdf09edb8fcc1a675695b8f99f src/db/tests.rs -23541660151d9005555a07db6d491455d61b185f0cc70c3ec3a0bee2aef08dc3 src/db.rs 19ab6c3ae37009c544291cb0b65c1bb9c721e168f95c1ed3fa88155aca7463ad src/demo.rs e69031875ffec32c9f548c43bed5f1a5c4c626e9568c9173e3b093f9a8b73036 src/diagnostics.rs +b45d6040810c93ae2acb04ef6b0a59c189751edf9008cd81a4521c9e04e7f07d src/docker.rs 93a8a3f6ba12761ddcbd19f22f32fb2c0e6948b660fb774ddd7ebdba9b6562a5 src/docker/client.rs 4c2c988191a97f81568a8df64af772463d010844f1abf327871901cdb32d4336 src/docker/model.rs 5f4610c59b2d4ff6a205a2d9ae11bc84be689b2a68302459f546b3f43e53593c src/docker/reconcile.rs a12c47df4b90b6fc36c978a42477e6ddffbbbf69aed7252101c2fd829709bd6e src/docker/tests.rs -b45d6040810c93ae2acb04ef6b0a59c189751edf9008cd81a4521c9e04e7f07d src/docker.rs -057e652f216a1478638cbb53b1c64ac88c7f413a65825caacbf893c5af004a63 src/forwarding/tests.rs 2a02ea2e010cde1b1fe99b2e6baa80ea344ea6b332dbb3c4be795b71541f64a7 src/forwarding.rs +057e652f216a1478638cbb53b1c64ac88c7f413a65825caacbf893c5af004a63 src/forwarding/tests.rs +af7a4e91c32ffbe4701c8c06e48ba3f8bbbe55e8b9e877aecb30ccdf858e9e8f src/geoip.rs 80850f7acd1ed4c0048b065e9e81740869a8efbb0d9b5d2e83d8ec7fbc494703 src/geoip/mmdb.rs 06aa056d789742cc11c8826c338d985e6a6fb22da6c3530937eec38e35478034 src/geoip/mmdb_tests.rs d3dc58628683472ef4d205fa5c42f0b7ef83cf90846146d96941cd3b36a40766 src/geoip/tests.rs 70091bdf6f38f03b6df8c8c4407c300677e57f293130122503f936500963d37c src/geoip/update.rs c1b49bef28d87712e4c46138e70b52c4bcfb1a00196579031fac043d0b4aaa7b src/geoip/update_http.rs 9a912dad0b8d1e10410fd95d0da3684656092ef85cf8b23eda4ffe7fb92921d8 src/geoip/update_tests.rs -af7a4e91c32ffbe4701c8c06e48ba3f8bbbe55e8b9e877aecb30ccdf858e9e8f src/geoip.rs -e4f07bfb7eb75b6897ef812870caff158679a3046d64582428abe8c6df490dbe src/headers/tests.rs f6ebafafa82391f8cb3b5a09331f3762b6ca5a9fb64bafb5772cde3ab814dfcf src/headers.rs +e4f07bfb7eb75b6897ef812870caff158679a3046d64582428abe8c6df490dbe src/headers/tests.rs +9e21edc67a14ef8a2ce3dda0ed18784d0fd0be305973e5d216058b7ac802c6cb src/http3.rs eb57117938a447d9a6c2ec1806ebd9fecc640a68c88950a8b35fa9bad14d0dc6 src/http3/body.rs ed25da264a2d25b40c4fcddc97c626a3a43d4f3a9be6c6d31af58b9e4925c198 src/http3/diagnostics.rs 37f54961d8f52b79a75fb2be31e81f4fdb1e66b06350345c4483d6197b8a0bbc src/http3/identity.rs f2a8c2a98f4ccfb708f9d75a48ec7b351232be9b8a4364b7e63ba14d28eead7c src/http3/settings.rs a31db7eac12b578b1eb5a74fae98bbe36312da95b7d7173135dbc41fc454da21 src/http3/tests.rs -9e21edc67a14ef8a2ce3dda0ed18784d0fd0be305973e5d216058b7ac802c6cb src/http3.rs 68fb5ab6a889995a66ad12cb6acf88c5d04f0aca572e2ae15f1a9cd171a5f24b src/lib.rs +2551189a3e5701371026c9abd2c5d44d37495f28fb67e220180421bfd315e3dd src/logging.rs 18c8d74c21a47f234be93551d7264b1f8f8c00d1bbfbe555d91618c58cea0740 src/logging/error_runtime.rs 33b4b7f69560c2acc0de0eac62604161d38dbd7044c5789a1352f0cd3882ea70 src/logging/format.rs f5815d778cc1785723faed4abb15f9880f22b6524b5289fe1e7158905aac0986 src/logging/model.rs 42fef80af50735cd566c6801dad86ba81be98cf4a8ec7d45c2ea26f53f556a22 src/logging/runtime.rs 584782215ea78a88526cdb5515031d8d5b87910875e26c0024b93a06680f6791 src/logging/tests.rs -2551189a3e5701371026c9abd2c5d44d37495f28fb67e220180421bfd315e3dd src/logging.rs +3836ed14b6710e183f048ee4d7807a35366c27a27338057fe4a2811129b63302 src/main.rs fc8e99eac83c083d65101f6402aacbcc8392d66508c31566a50de3ebcb12e7da src/main/admin_runtime.rs 42a9197475823f67c1ca762951ede5d7a2f10124bd6ed4d1a3365f4297be894c src/main/bootstrap.rs 5a98d0e249338e73aa57ae2e352dc16db2f79c2d042c1544ce1c2022da76a31c src/main/proxy_runtime.rs -0a6578a0f4023b9f8d73043bf942dc5e096ef9afb8c0d2f131c14f65d08ac01d src/main/shutdown/tests.rs 4dd7c1084a6214c0f2513ebf86fe8ef144470695557772bfe25979edd64491ab src/main/shutdown.rs +0a6578a0f4023b9f8d73043bf942dc5e096ef9afb8c0d2f131c14f65d08ac01d src/main/shutdown/tests.rs e5c2e9189777725f4afa1c3c052e4f75047ec3f2f486630d990f5d3c194bcc96 src/main/tasks.rs -3836ed14b6710e183f048ee4d7807a35366c27a27338057fe4a2811129b63302 src/main.rs -201ab702722d6d21585fe8bb49939150d61bfac7ed8dc198b98c2cc6098ffb5f src/metrics/global.rs -a54b5b34ea65f29723b89b81bf7968a238e8247b9c9760f3430d3504cb1017c9 src/metrics/vhost/tests.rs -49b11df65b4fb0b5b727f9f867436584680b45e3f4fbd53f74bc0cab8b9a88ec src/metrics/vhost.rs 49d7e104585c8791ac9a203dddd95802784b68c0ba65d6f90f3d57154b4c7871 src/metrics.rs -c915d30bbd7032d867e7916b4cd45f3bb7e7604d3f4558f4383c59394b4300c6 src/not_found/tests.rs +201ab702722d6d21585fe8bb49939150d61bfac7ed8dc198b98c2cc6098ffb5f src/metrics/global.rs +49b11df65b4fb0b5b727f9f867436584680b45e3f4fbd53f74bc0cab8b9a88ec src/metrics/vhost.rs +a54b5b34ea65f29723b89b81bf7968a238e8247b9c9760f3430d3504cb1017c9 src/metrics/vhost/tests.rs a4702c95c7e5077c2ccff86e2e3216e1da6ff9ee4383ae199a0aff2f78db325f src/not_found.rs -da40e8ece87245efc49a0c4e750526b1d19fd97565856bd5caf641fcc1dfe18d src/pages/tests.rs +c915d30bbd7032d867e7916b4cd45f3bb7e7604d3f4558f4383c59394b4300c6 src/not_found/tests.rs d66936cc15fd5d56566d40fa8cab93f80d94b05f10ac44478a30f63572a95e32 src/pages.rs +da40e8ece87245efc49a0c4e750526b1d19fd97565856bd5caf641fcc1dfe18d src/pages/tests.rs +0dba7b6a33866cc7bbe05509b01961e545892645d1dad4eb88ac8a4bec65e3bf src/prometheus.rs cc6fb14351b009a16d07ed0f412c2bcc68cd7e551421aea03d8d97ceec9bee40 src/prometheus/core.rs c46882ed26742d93806a976257674326e105b8ca1fc23f5ca81e317b268057aa src/prometheus/docker_misc.rs d3c6b08088df0003144544936a55e2a3661aac85292821b594f00adfd19a2951 src/prometheus/model.rs @@ -425,13 +429,12 @@ d3c6b08088df0003144544936a55e2a3661aac85292821b594f00adfd19a2951 src/prometheus 028e1dd9f2ec2afaf699a6b21c2d4b0d96e76f11f5e4ed009c233dadf0f3be51 src/prometheus/traffic.rs e03f0d6b3f35dae6b98c394837aa0d17e4d73a8306767b4c607868bc00c30286 src/prometheus/vhosts_backends.rs fb2d8d45cd2e947f783eb981b37fa418c39fcb327a3af17a648fadea7f37f888 src/prometheus/web_php.rs -0dba7b6a33866cc7bbe05509b01961e545892645d1dad4eb88ac8a4bec65e3bf src/prometheus.rs -f0f3e21350e4fb15fa2ae282da6b290857dcd6716e62b183e9ecb728b7c24c63 src/proxy/body/tests.rs 4c7199c04e6d314e89825f80feaab35a2efb3b893511f70da0cda46ab1d0bc9e src/proxy/body.rs +f0f3e21350e4fb15fa2ae282da6b290857dcd6716e62b183e9ecb728b7c24c63 src/proxy/body/tests.rs b88d1d7a6837a2a470e5863f1f3247878daee62791fc3d8e72baeb66469bdfbf src/proxy/cache_helpers.rs aa49c9928bb91e3d5bae0d340d88396a0417b9edec6192d41e1403533319a897 src/proxy/cache_http_invalidation.rs -3404b03096862de1050088f62cdd811ea1ab61d191f902501173107f81f23b9b src/proxy/cache_plan/tests.rs 676c1b325fd8e55bcdd86451c7d1d8b8d347ca00e8da6b3e5b148a58c376a9b4 src/proxy/cache_plan.rs +3404b03096862de1050088f62cdd811ea1ab61d191f902501173107f81f23b9b src/proxy/cache_plan/tests.rs a8848cbdf85368548b003af2b43823c453866c472af4c7d2ff0ec7da14c44c8d src/proxy/error_fallback.rs bf2e6bbd64fb45fceed54af0bff1c1e00da22b79c64dd8f5c23d2af0dbab0b7d src/proxy/forward/cache_lookup.rs cfa941b60b5d167ec9d8e2566ea3342b588d1a9078a6ca711ad6062ddf00fec9 src/proxy/forward/response.rs @@ -442,123 +445,123 @@ bb24da9c9ab986a9c4d4144d4d1be0f661561d4afc755f298b58bc679b182850 src/proxy/forw 11dccc239ac8a8e9ea06e884c2f2658f86b7807d14a59b8e052bc7dd75e86d63 src/proxy/forward/web_source.rs facde401ba5bcbafdcea5524f236cfae37eec11144ceeea879e83314c84bc97e src/proxy/forward_entry.rs 9b25f5e3ea4443a63ee6f45d12e1957dd316fe8e85325fc00ea416faaab1025a src/proxy/h2_graceful.rs -5cb7522ceb9a9f083a15596ac4898559295e38d1138c80099577211de8a868ec src/proxy/headers/tests.rs c438066616527a3108f2ad53e3698ae9b2a80961714394cdd0a450c92f99d992 src/proxy/headers.rs +5cb7522ceb9a9f083a15596ac4898559295e38d1138c80099577211de8a868ec src/proxy/headers/tests.rs 3f25429418941eb72c3847125340db74684ad316eb278ecf658953026fd41f4f src/proxy/mod.rs 55133ceace2e5262d9c54fa41bea099a27b817d1e09c1cd0e2493fd9cee4da38 src/proxy/redirect_helpers.rs -6ff45990f6beb914e89924bec2c41022f3240a14357cf66ec4f8ada414a49767 src/proxy/request_id/tests.rs c61738672f210e97333c8c89f9b35f8db454cbc1c36955288dfa4cfff2bbbc04 src/proxy/request_id.rs +6ff45990f6beb914e89924bec2c41022f3240a14357cf66ec4f8ada414a49767 src/proxy/request_id/tests.rs 8ad3619359f3befa14ea71ba43c638fea8f4d8a859cd07e4ed505731b8e32e72 src/proxy/tests/authority_tests.rs 1aa9bbbfb2659facdaeaf185e11221b1c8cd5fe6e23c7c1dacd3aa55e3db4fcb src/proxy/tests/cache_fast_path_tests.rs 0f2eacadf1447db8aa1c1a78005aa262e0f747096bfe7e0a0e41a2cd31a0d17f src/proxy/tests/h3_navigation_tests.rs d134b0eb617f82f9971b3f3461379ea37c57bd0079bf54748d0c434b2ef1b475 src/proxy/tests/http_invalidation_tests.rs d5717fac0e7d2cb2939626eb95f4520241b677fe1f3e045df12c100315302a5a src/proxy/types.rs 8d7848645c25932589d0dfc54149bb71a51edd7188aed60dc4d6ca8179b361ab src/proxy/upstream_helpers.rs -d7b4b809b12ee89293df45e9a64b1c9981fb3f89deaab3762f4a3ad3992dd7b1 src/proxy/web_cache_revalidation/tests.rs 2d9142e3ae95895b5271b4009ab48236a3a2074ce51179c021193b35777560e4 src/proxy/web_cache_revalidation.rs +d7b4b809b12ee89293df45e9a64b1c9981fb3f89deaab3762f4a3ad3992dd7b1 src/proxy/web_cache_revalidation/tests.rs +69f775f6746b4c6d729dc10961dbef54168846f4ce9cf7fe453ab5a2b879c9b8 src/proxy/websocket.rs d866e7e72dee6ff54c2418c34e9899cbcd7e4e027d9cbe2b625044dc9062e4ee src/proxy/websocket/handshake.rs 7e9c4d4c207badabf90630223964bb2ad641f06d4149843cab751f192b8b4adf src/proxy/websocket/tests.rs a44421714aab37f7ceda19e3ec2512c645d2a3ce5dcb3da5bc7a0d87a442d6a8 src/proxy/websocket/tunnel.rs 15fabd38576b61f650c039acdbf7ac5a5bd24330062475b94315285b2dc258b6 src/proxy/websocket/validation.rs -69f775f6746b4c6d729dc10961dbef54168846f4ce9cf7fe453ab5a2b879c9b8 src/proxy/websocket.rs -e7e3a898e2c769b1ef11e58a13c1053104ada93dd694f8a03ea4b647c44c7d69 src/rate_limit/tests.rs 545247eb00b0116efbd4cc913cc251195a55feded1530e0d8d8945abbae78039 src/rate_limit.rs -811c83ae9fd0f5a13d35b5443cd37843f82b9d600bee4bb136ba9b87732a5347 src/redirect/tests.rs +e7e3a898e2c769b1ef11e58a13c1053104ada93dd694f8a03ea4b647c44c7d69 src/rate_limit/tests.rs d40ad63939097d2b91339127d5835a74b618d83b7ba31db0c512f05a82107d6e src/redirect.rs +811c83ae9fd0f5a13d35b5443cd37843f82b9d600bee4bb136ba9b87732a5347 src/redirect/tests.rs +d0939e1b0829c25356a0b67ecb3a178c74936dd07baa15fee24eb32544db6cad src/runtime.rs 8d0d7b01871c8c588c40a54330a1053c85024655fbe38516ca6c94c3c19a8956 src/runtime/certificates.rs 2ccafa8a5a8462417f65d05a0c6c42f294afa4ad1067ea0b93623181546d1f96 src/runtime/constructors.rs 92b4b284f1b69dca58e4e3f76199f0aecc397eed26d10123b427af1bb8a4a57e src/runtime/docker.rs ee2050b9f8efb45a209c91d76043a1ba29c4289978896aaf7e7d344d48fdc369 src/runtime/tests.rs 779137f320133ec96f73c8b3d357ad4f0b825ee2367e9e8300f4f143b38eecb7 src/runtime/types.rs 5947afaf7d070ea2047eb7969a8e0d84f981e91ace283f6506cf7685fb8afab9 src/runtime/updates.rs -d0939e1b0829c25356a0b67ecb3a178c74936dd07baa15fee24eb32544db6cad src/runtime.rs -6dca8da072a3bd610704a391bb6e25c9042971f4ebc60edb47665ce1d74cbc58 src/secret_store/tests.rs 208a378b14ca80e1412ffa19ef1b140594182971e2e797ee0bb95bcdb8404da7 src/secret_store.rs -0e5fc2aff856bf6fd959cba12b5ddd1e3b3cbeb0fbaadde906c811cdfafdaae7 src/security/tests.rs +6dca8da072a3bd610704a391bb6e25c9042971f4ebc60edb47665ce1d74cbc58 src/secret_store/tests.rs 6fa1d8c352bce7a16ff0208bc4cdbe80404715df0aff4ed26910a5df57cbbcd4 src/security.rs +0e5fc2aff856bf6fd959cba12b5ddd1e3b3cbeb0fbaadde906c811cdfafdaae7 src/security/tests.rs +98c52aa3b50d2e211ab752ccaf353c9a8c1500a87f9c1684b5dd0ba9d10e4619 src/server.rs f2f6196632b2fdb2444189624f961edaf5bdfff57f700b0207b57e2491c1daa5 src/server/http.rs 050c48ea1127aa87dba92c074ab84e8346e65dbe253621ea53f8ca2f68d791ab src/server/http1_connection.rs 8c6ca5eaffb9acab57199d0349722703b903cfff3752baad2cf2596bd51188de src/server/listeners.rs 4424a99b0b688d1119ee25626778b4804aedfaa0799a4a9bc0ee99bc5c7ba96b src/server/sendfile.rs -e9e478cf45b88994eaffd115f51764b6b07852ee3c941cafdabb20584d3dabc0 src/server/serve/tests.rs 71899a9b1897fa22ab9e8eb6a670054a6d382bad78714006b9b218d07ba99902 src/server/serve.rs +e9e478cf45b88994eaffd115f51764b6b07852ee3c941cafdabb20584d3dabc0 src/server/serve/tests.rs 960a82e02f09d75141fe3c1eecca915b66f17fdc8167196cd2fe21d5e6859376 src/server/tls_runtime.rs -98c52aa3b50d2e211ab752ccaf353c9a8c1500a87f9c1684b5dd0ba9d10e4619 src/server.rs +73ec453ac2850f6963f5bc33401cb8c92aa26d5123f15d68e6633860d91f265e src/settings.rs 240ecdd70e8662ff3b84c21830dc0cbbbacadd755d56146e54214bc2887f068c src/settings/public_origin.rs 1f1121c3562c8f8f3fdee2113be2afffb8849be2d303e4c4409f87478b6e3307 src/settings/tests.rs -73ec453ac2850f6963f5bc33401cb8c92aa26d5123f15d68e6633860d91f265e src/settings.rs +9dbf814870b8636770f579c3d36d16f5b6afe8bc66adfad356c26d7ae7dbce45 src/stream.rs 254840126be2310426f6332f5efbe98147d9d8de1999731f40a3d13325c1dc6c src/stream/health.rs bdc56be7dae85a97a4d5b8d46ef31ec4177292b1cadd507fe423b6d4ee1403bd src/stream/model.rs de138a4ac68bcddba3a4f17ceba008bab643359d76a68726a755069f19334bed src/stream/pool.rs 6ec42b8647c95a0c2025462e0be29c71481ce1c3b1f4d4193926471f1cf06be0 src/stream/runtime.rs 9346cbd71e006e41a7188f28eb86f9b00bac822e4cb31c76c8d6d2ec5d4c4711 src/stream/tests.rs -9dbf814870b8636770f579c3d36d16f5b6afe8bc66adfad356c26d7ae7dbce45 src/stream.rs -d9123c623e2a97d09e41edaa29993b4b2c8cba39a3abdf2b48a205aa9a9c2939 src/system_stats/linux/tests.rs 3070d78a7b88c2e47ed59960fa35e7d220a4cd7d78e48f6c6d2bcc5ff77f9620 src/system_stats/linux.rs +d9123c623e2a97d09e41edaa29993b4b2c8cba39a3abdf2b48a205aa9a9c2939 src/system_stats/linux/tests.rs 751d59582fb92c84e0c0cc7c0855c9d0a545805c9ba3be61826e50fb96c297ed src/system_stats/mod.rs 050aa831b1012c4aaade63863f433f01bfacf5d3f95787e57975572116a30ab2 src/system_stats/tests.rs -0e1d87554db55e724f30c41ec4a5c80bdb8fc9c8cba8700ac509864d4abf8871 src/tinyauth/tests.rs 7467d83066bb6986d8c9103597f7a7617ac677579ed46d573c573ff6ca57bbd9 src/tinyauth.rs +0e1d87554db55e724f30c41ec4a5c80bdb8fc9c8cba8700ac509864d4abf8871 src/tinyauth/tests.rs +1084cccd9de28acd6cb0f0813de7c0953910f51726f73f4acdb2e3ada4593976 src/tls.rs 4972a436f8878dec5f9eb8ff17eb82670b0bfd9e94e821c516575479f5fc1919 src/tls/certificates.rs 436575144aa352498a4696f12c2258bef3a898f3f50e6fbc6d67c3b93afa099f src/tls/external_paths.rs 3e6947dde167f82a5efc407ccf9bd4c9f5b26cc8633d1418a10284bc1a1503d4 src/tls/server_config.rs +31c0f51a3a0bab433f438c3ba1b1cdaf3c63fae6086e7d99b3464a537f75a5e1 src/tls/tests.rs 2af2164ecdf2b7fd9eef7c6e358dec053dfac9aedaa501dbb75df742d18638b2 src/tls/tests/acme.rs 93b359e9defd62506729bc90e56c96783e2f14dd477dd67f337ca83149da7168 src/tls/tests/external_paths.rs -31c0f51a3a0bab433f438c3ba1b1cdaf3c63fae6086e7d99b3464a537f75a5e1 src/tls/tests.rs 10c4a187e3aeb0c72a8c8968ea0cc8bfae4e3cb2f3d834ebd3da1056c4171ec5 src/tls/types.rs -1084cccd9de28acd6cb0f0813de7c0953910f51726f73f4acdb2e3ada4593976 src/tls.rs -36301bcbd20b557dd3d58e77a9175f3581947f577c0bb0b972899cec6786b03f src/traffic/tests.rs c2f802d95da4332fb8480e83f0c7502334457b3408141c1c4516c9ba320a0463 src/traffic.rs +36301bcbd20b557dd3d58e77a9175f3581947f577c0bb0b972899cec6786b03f src/traffic/tests.rs d88c92f5a2a7773bc3e715d24039db35da4df53881f1a0859eec819b96f06d3b src/transform/apply.rs 87f8af5261d79072f8215f1fb8a90715a58e7626544fd8176ce840e3111bdb92 src/transform/compile.rs b2c5236589093454ec60984b785ad6a4af6149d47f6db37d8e08c17fec7a2c1b src/transform/css.rs -aa99b0d3029ef92c78371cb90e11f2026cce890d1be8e10ebd7fa9bc5cb13287 src/transform/html/tests.rs 5478670cef87777b14a2dab308f5a9182df56d7ea2f5625bdc94aa7e3d661503 src/transform/html.rs -cf5195ab6bacccae0082da7b3f1bd0382b73fdeb3607f4ae569ca6daab9d10d0 src/transform/js/tests.rs +aa99b0d3029ef92c78371cb90e11f2026cce890d1be8e10ebd7fa9bc5cb13287 src/transform/html/tests.rs a1d2fec07617c8a8dc425bfaeaf77c844152a0a174568a88a5baf4c317cc6c5c src/transform/js.rs -216e24e29ea87be4a124f95f898e155f127fd959d7d5d9b30f8cd0b2b5018f30 src/transform/json/tests.rs +cf5195ab6bacccae0082da7b3f1bd0382b73fdeb3607f4ae569ca6daab9d10d0 src/transform/js/tests.rs 226ae561dc7b0243c04e55e28cdfd2b76acd48cf614d1919b81c196660b03cfb src/transform/json.rs +216e24e29ea87be4a124f95f898e155f127fd959d7d5d9b30f8cd0b2b5018f30 src/transform/json/tests.rs 6a8c28be93fb590942493c075b29ace1527981542bd183f232aa82b62e951eca src/transform/mod.rs fde2fa3aa94b30d8536afec1c11348cfbd922d0b5ff89e91d34266e8e3863e26 src/transform/model.rs -0f53c64f442390ee20a59087a10f8f9ffb58053263e9aa848ddabfae1a6f3f51 src/transform/svg/tests.rs a4e1d2aa2913587c250f251356431097b76995aee6e8bf9e35c4978a95491de1 src/transform/svg.rs +0f53c64f442390ee20a59087a10f8f9ffb58053263e9aa848ddabfae1a6f3f51 src/transform/svg/tests.rs d1f3f53fedae0d8ef69eeee457f7d30ed5a670a1ed4ced60683400ee46680260 src/transform/tests.rs -c42d000d1d576721af3ffe930589388693001b8113554a7658f6dcbc665b5d1b src/update_check/tests.rs 6146c59f36cf419623747d497b3de685da6c84964df43317bebdcb21deb9ee09 src/update_check.rs +c42d000d1d576721af3ffe930589388693001b8113554a7658f6dcbc665b5d1b src/update_check/tests.rs +92efcdaafb9f5a8514daf63d7fcde29be977d7bdcd90162eda0ce00d6967ffbd src/upstream.rs ca695e246bee5389b3757fe8588e48bff5d0ad473bc8588ad4ba7b52c99d7dfa src/upstream/client.rs ad29f3fc15c9b627b5d752af5adc9f99ee1364fec2df63f1e4509cb223988efb src/upstream/client_tests.rs 75fef0a488d3f3dabfa03c2eabc5995442dfb3c9a1fde8eb6653a124dda25d43 src/upstream/protocol_tests.rs 8a112154b9631f62a54584302a3ff6a64e4f177ce79aba678b4cb23e466c6ea3 src/upstream/tests.rs -92efcdaafb9f5a8514daf63d7fcde29be977d7bdcd90162eda0ce00d6967ffbd src/upstream.rs -6d7cb73de7d8c6f3780736480f5f81ef08813f4626fd5ed494aca0552cf214a1 src/user_agent/tests.rs a6b4905c245a22eafb1aa535d303d0fa24e4353db94e1d67fd42b825bf8c5adb src/user_agent.rs +6d7cb73de7d8c6f3780736480f5f81ef08813f4626fd5ed494aca0552cf214a1 src/user_agent/tests.rs +3aa1b07cd26d4a5b9e5e94d1d6a712ef1397d827e7f1e8c01f7195b98d2c5f67 src/vhost.rs 6678192de56bc10c5cf82bdff8da14eece7685f409592450c07478333aa3b99c src/vhost/error_fallback.rs 63e9fc7f7be78dc3e16a89f015a56a2da6ba3aff0197b70ff48321dfb17529bb src/vhost/model.rs 35a0aca3eee8d47d1bab27c83d4532cd572fc3e17b5f0d4a8d4515a8f85b3d96 src/vhost/redirect.rs 9b16b5307e140db97363f56c9fac8319e56df846bb1c919d3bc06091ab6ce69c src/vhost/tests.rs b7d0f7f5d0bbd74add3fda9b1308350c4f70f8b6debf979fb977a4f2f659c32f src/vhost/validation.rs -3aa1b07cd26d4a5b9e5e94d1d6a712ef1397d827e7f1e8c01f7195b98d2c5f67 src/vhost.rs +8d1eff4b24f01d137414ef5419f75dd281879228adb70409645b11b3c78c20e9 src/web_server/config.rs 9744e8c29ae72a4d9fbc9a76166a97f8292c4c312295ea40d1cb699e03d80a9d src/web_server/config/compile.rs bcaa1ae15134d85668b05a88d8abea01e5d188f535ad83cd4459732fd56f2f44 src/web_server/config/model.rs a863ad1337fbc353c0f42caea4ac8b3644792e2aa08c37f992b7882b4b8dc6d5 src/web_server/config/validation.rs -8d1eff4b24f01d137414ef5419f75dd281879228adb70409645b11b3c78c20e9 src/web_server/config.rs +86c744216d7132d8294a6e90ba9be5fd871646006313d1c62506d40c81db9b12 src/web_server/fastcgi.rs 200cba8cb3482e49db73d2c60cb60786175177c7d4be2a566cd281fec7ba7fca src/web_server/fastcgi/protocol.rs cef44ccdf882d84892a64bdbfdc1ba01380fce5e5f86d2829b0f9613f738b964 src/web_server/fastcgi/response.rs -86c744216d7132d8294a6e90ba9be5fd871646006313d1c62506d40c81db9b12 src/web_server/fastcgi.rs e15361622683268c5606a39a9e5db3938e630999767898391226e94ad2e421e8 src/web_server/filesystem.rs +d4fec3682532b0f2d11a0aefcd024f69fb623a39922ddb6c528a2d2de265347d src/web_server/htaccess.rs ca3cd376b313af1ce0ee65081b3327eb213f000d5a215aa4ee6b764de9702126 src/web_server/htaccess/model.rs 76de1d11df75f4a64556b2821fd0a1774d26c9f0ca0e5f2b5fcfad0722d43d47 src/web_server/htaccess/parse.rs 66260d159986d41eab0dfde2cb9f0713fc1cc209c2fb47e9023bd24fd37919e8 src/web_server/htaccess/rewrite.rs 8ca74d9cc4470045301f70eb4a9fbabd0dbfe74434429148d2230df9f996c06c src/web_server/htaccess/tests.rs -d4fec3682532b0f2d11a0aefcd024f69fb623a39922ddb6c528a2d2de265347d src/web_server/htaccess.rs 3341264f6e8041ac5a5d3c4b1601a69787386116019b5febc1a5e22bdb1186f9 src/web_server/metrics.rs 0dbef9b71869fc52cf01e9cb400ffd48fb433ae625383edee6c6c2d735608a76 src/web_server/mod.rs 67ab8bef567452f123c4b9b46a942b39c93f1f765c128edca7ee808ff1c5e304 src/web_server/request.rs -833c9fea744b9649046e1a64d6fc6972fbf6cea640e1943b0db52b7ccfa9faad src/web_server/response/file.rs -c2e54fd803a10f74490f183e8c030fd0e3e72f5de4e79c55bc393ab57d90ab9a src/web_server/response/file_body/tests.rs -ba793a140699956a9aef6bc79b0c731c481af8ab7ac3d816a28695743febcb30 src/web_server/response/file_body.rs -20509f9302b79d3a7be76dda6edaf5711826d3ddf47d19ebe07cb289427ca328 src/web_server/response/headers.rs d98c80663847d6d83073df074ebff65952755415574708abcc153bd8d3adfaa9 src/web_server/response.rs +833c9fea744b9649046e1a64d6fc6972fbf6cea640e1943b0db52b7ccfa9faad src/web_server/response/file.rs +ba793a140699956a9aef6bc79b0c731c481af8ab7ac3d816a28695743febcb30 src/web_server/response/file_body.rs +c2e54fd803a10f74490f183e8c030fd0e3e72f5de4e79c55bc393ab57d90ab9a src/web_server/response/file_body/tests.rs +20509f9302b79d3a7be76dda6edaf5711826d3ddf47d19ebe07cb289427ca328 src/web_server/response/headers.rs 305c0109b4f869a99381a142853f9e2205f5c7c4f904b2dfa4643274bfc542af src/web_server/routing.rs 400e1c8aa2fe857d96036a64499fbc3de44c1e3a53811c5b25101fb843359792 src/web_server/security.rs 54cf72a82e023fe46513b9cf3130adfef1cd96c40f790c533016b4825d542e06 src/web_server/serve.rs diff --git a/docs/RELEASE_0.34.0_CACHE_FIX_PL.md b/docs/RELEASE_0.34.0_CACHE_FIX_PL.md new file mode 100644 index 0000000..3f3c1e4 --- /dev/null +++ b/docs/RELEASE_0.34.0_CACHE_FIX_PL.md @@ -0,0 +1,93 @@ +# RustProxy 0.34.0 — poprawki cache, transformacji i kontrola RPS + +Status: **zmodyfikowane źródła, niekompilowane lokalnie** (brak `cargo` i `rustc`). Numer wersji: 0.34.0. + +## Co odtworzono na binarce użytkownika + +Uruchomiono binarkę Linux ELF w izolowanej konfiguracji z lokalnym origin HTTP, z włączonym cache, transformacją CSS, `max_ttl_seconds=86400`, diagnostyką i API administracyjnym. HTTP/1.1 localhost, pełne GET, brak kontaktu z witryną produkcyjną. + +| Odpowiedź | Pierwszy GET | Drugi GET | Liczba pobrań z origin | +|---|---|---|---| +| `/normal.css` | MISS | HIT | 1 | +| `/aged.css` | MISS | MISS | 2 | +| `/br.css` | MISS | HIT | 1 | +| `/aged-br.css` | MISS | MISS | 2 | +| `/private.css` | MISS | MISS | 2 | +| `/no-store.css` | MISS | MISS | 2 | + +Zwykły CSS i skompresowany Brotli dostają HIT. Warianty z `Age: 1553483` mają `MISS → MISS` mimo `Cache-Control: public, max-age=2592000`. Przypadki `private` / `no-store` słusznie nie trafiają do cache. Zmiana keep-alive vhosta nie usuwała poprawnie zachowanego obiektu. `expose_only_hits=true` celowo ukrywa nagłówki na MISS. + +## Główna przyczyna i poprawka + +W `src/cache/policy/response.rs` obowiązywał wzór `ttl = min(origin_max_age, local_max_ttl)` oraz `remaining = ttl - corrected_age`. To jest sprzeczne z zadaniem lokalnego limitu: świeżość w origin nadal trwa, ale CDN `Age > local_max_ttl` dawał sztuczne 0 sekund lokalnej świeżości. + +Poprawiony wzór: + +```text +corrected_initial_age = max(apparent_age, upstream_age + response_delay) +remaining_origin_freshness = max(0, origin_max_age - corrected_initial_age) +remaining_local_freshness = min(remaining_origin_freshness, local_max_ttl) +entry_fresh_until_age = corrected_initial_age + remaining_local_freshness +``` + +Przykład z przesłanych nagłówków: wiek upstream 1 553 483 s = prawie 18 dni. Pierwotna świeżość 2 592 000 s (30 dni), więc pozostało około 12 dni w origin. Po naprawie RustProxy będzie mógł przechować świeżą odpowiedź przez lokalny limit (domyślnie 86 400 s = 1 dzień). Nagłówek Age nadal będzie około 1,55 mln sekund i będzie rósł na HIT — to poprawne. + +`Age` nie wynika z `Last-Modified: 2016`. Najczęściej jest przekazany przez upstream/CDN, a stara data `Date` też mogłaby podnieść apparent_age. Rozróżnienie: `Age` = HTTP wiek całkowity; `resident_age_seconds` = pobyt w HOT/COLD. + +## HOT RPS i panel + +1. HOT HIT nie wyjmuje już i nie wkłada od nowa wpisu oraz indeksu `Vary`, tylko aktualizuje licznik HIT i kolejność LRU w miejscu. Zmiana ma zmniejszyć alokacje i krytyczną sekcję; **zysk RPS jeszcze niezmierzony**. +2. Panel Cache ma osobne kolumny **Age** i **Czas w RustProxy**. API `dashboard.objects[]` dodaje `resident_age_seconds` także dla COLD. Pozostałe nazwy pól nie zostały zmienione. +3. Licznik `x-cache-hits` dotyczy konkretnego aktualnego wpisu. Gdy obiekt zostanie wyparte z HOT (limit wpisów/pamięć), usunięty lub zastąpiony po MISS, licznik restartuje. W próbce użytkownika TTL wynosił około 604 tys. s (7 dni), więc późniejszy MISS po ~4 minutach **nie wynikał z normalnego wygaśnięcia TTL**. Konkretnej przyczyny epizodu nie można ustalić bez trendów `evictions`, `purges`, `hot_demotions`, `cold_hits`, kluczy/Vary oraz zmian konfiguracji. +4. Brak `x-cache` na MISS jest oczekiwany, gdy włączono **nagłówki diagnostyczne tylko na HIT**. Brak wpisu w API może mieć inne przyczyny (np. cache-control `private`, `no-store`, brak polityki origin, limit obiektu) i nie należy ich obchodzić na siłę. +5. Nie zmieniano uprawnień, `private`/`no-store`, kluczy Vary, TTL po stronie origin ani zasad selektywnej invalidacji. + +## Wynik symulacji TTL + +Wykonano **100 000 deterministycznych scenariuszy**. Dla każdego sprawdzono: po naprawie lokalna świeżość nie przekracza `local_max_ttl` ani świeżości pozostałej w origin. + +| Scenariusz | Stary pozostały TTL | Po poprawce (symulacja) | +|---|---:|---:| +| Age = 1 553 483, local cap 1 dzień | 0 s | 86 400 s | +| Age = 1 553 483, local cap 7 dni | 0 s | 604 800 s | +| Origin kończy świeżość za 10 s | 0 s | 10 s | +| Origin jest już nieświeży | 0 s | 0 s | + +W symulacji 33 387 / 100 000 losowych przypadków stara polityka błędnie dawała zero zamiast dodatniego TTL. **To nie jest procent regresji w realnym ruchu**, a wynik losowania parametrów testowych. + +## Nginx — rzeczywiste pomiary starej binarki + +Archiwalne wyniki samej binarki `rust-proxy 0.34.0` na tym środowisku (Linux, 4 vCPU, HTTP/1.1 loopback, ApacheBench, 64 połączenia, cache OFF, 3 powtórzenia), z nginx 1.26.3. Brak miarodajnego benchmarku **nowych źródeł** przed ponowną kompilacją. + +| Endpoint | RustProxy RPS (mediana) | nginx RPS (mediana) | RustProxy / nginx | +|---|---:|---:|---:| +| proxy 1 KiB | 10,544 | 58,709 | 18.0% | +| proxy 64 KiB | 7,893 | 17,358 | 45.5% | +| proxy 1 MiB | 1,010 | 1,666 | 60.6% | +| www 1 KiB | 11,984 | 71,318 | 16.8% | +| www 64 KiB | 9,224 | 26,600 | 34.7% | +| www 1 MiB | 1,264 | 1,098 | 115.2% | + +Ograniczenia porównania: ApacheBench może limitować klienta; wyniki nie reprezentują TLS/H2/H3 ani ruchu produkcyjnego. **Nie wolno tych RPS przypisywać nowej rewizji.** + +## Zestaw testów dla nowej kompilacji + +```bash +CARGO_INCREMENTAL=0 cargo test --locked --lib +CARGO_INCREMENTAL=0 cargo build --release --locked +python3 scripts/tests/cache_age_policy_034_model.py +python3 scripts/tests/cache_age_transform_034_live.py --binary target/release/rust-proxy --output /tmp/cache-test-034 +python3 scripts/tests/cache_scope_034_static_test.py +python3 scripts/tests/proxy_hotpath_034_static_test.py +python3 scripts/tests/sendfile_034_static_test.py +``` + +Do testów jednostkowych dodano Age, transformowane CSS/HOT, democję do COLD i odczyt COLD po restarcie, logikę LRU/HIT oraz kontrolę zakazów `private`/`no-store`. Test lokalny sprawdza CSS/Brotli, origin count, API, keep-alive config i ukryte nagłówki. Test po kompilacji bez przełącznika `--expect-old-age-bug` ma wykazać `MISS → HIT` dla Age/Brotli. Na starej binarce odtwarzanie regresji przechodzi z `--expect-old-age-bug`. + +Kontrole wykonane na źródłach: źródłowe testy cache scope, proxy hotpath, sendfile, składnia JS, parsowanie tłumaczeń. **Nie uruchomiono testów Rust ani benchmarków poprawionej binarki** — środowisko nie ma `cargo/rustc`. + +## Następny pomiar po kompilacji + +Porównać tę rewizję 0.34.0 z poprzednią 0.34.0 oraz nginx dla 1 KiB / 64 KiB / 1 MiB; osobno cache OFF, HOT HIT i transformacja/Brotli. Raportować RPS, p95/p99, procesor, RSS, nowe TCP, `cache.evictions` i `cache.purges`; nie modyfikować ustawień cache podczas benchmarku. + +Uwaga: `curl -I -X GET` miesza zachowanie HEAD i GET; do testów reprezentacji zalecane `curl -sS -D - -o /dev/null URL`. diff --git a/langs/en_US.json b/langs/en_US.json index 0ed8d10..57f6c32 100644 --- a/langs/en_US.json +++ b/langs/en_US.json @@ -619,12 +619,13 @@ "cacheObjectList": "Stored objects", "cachePrevious": "Previous", "cacheNext": "Next", - "cacheObjectHint": "Most recently used first. Click Target or Cache key / tags to copy the full value. Bodies and request headers are not exposed.", + "cacheObjectHint": "Most recently used first. HTTP Age includes upstream/CDN time; Time in RustProxy is the actual HOT/COLD residency. Stale retained objects can also appear. Click Target or Cache key / tags to copy the full value.", "cachePath": "Path", "cacheBodySize": "Body", "cacheAge": "Age", + "cacheResidentAgeValue": "Time in RustProxy", "cacheTtlRemaining": "Remaining TTL", - "cacheNoObjects": "No fresh objects in this scope. Inspect the decision counters above.", + "cacheNoObjects": "No stored objects in this scope. Check the vhost filter and decision counters.", "cacheLegacy": "Unassigned", "cacheGlobalLimit": "Global limit", "cacheFills": "Active fills (global)", diff --git a/langs/pl_pl.json b/langs/pl_pl.json index d0cd46a..ad7a5bf 100644 --- a/langs/pl_pl.json +++ b/langs/pl_pl.json @@ -619,12 +619,13 @@ "cacheObjectList": "Zapisane obiekty", "cachePrevious": "Poprzednie", "cacheNext": "Następne", - "cacheObjectHint": "Najpierw ostatnio używane. Kliknij Target albo Cache key / tags, aby skopiować pełną wartość. Treści i nagłówki żądań nie są ujawniane.", + "cacheObjectHint": "Najpierw ostatnio używane. Wiek HTTP (Age) obejmuje także czas w upstream/CDN; Czas w RustProxy to rzeczywista rezydencja w HOT/COLD. Wpisy nieświeże mogą nadal być widoczne. Kliknij Target lub Cache key / tags, aby skopiować wartość.", "cachePath": "Ścieżka", "cacheBodySize": "Treść", "cacheAge": "Wiek", + "cacheResidentAgeValue": "Czas w RustProxy", "cacheTtlRemaining": "Pozostały TTL", - "cacheNoObjects": "Brak świeżych obiektów w tym zakresie. Sprawdź powyższe liczniki decyzji.", + "cacheNoObjects": "Brak zapisanych obiektów w tym zakresie. Sprawdź filtry vhosta oraz liczniki decyzji.", "cacheLegacy": "Nieprzypisane", "cacheGlobalLimit": "Limit globalny", "cacheFills": "Aktywne zapisy (globalnie)", diff --git a/scripts/performance/simulate_cache_034.py b/scripts/performance/simulate_cache_034.py old mode 100644 new mode 100755 diff --git a/scripts/performance/simulate_nginx_gap_034.py b/scripts/performance/simulate_nginx_gap_034.py old mode 100644 new mode 100755 diff --git a/scripts/tests/cache_age_policy_034_model.py b/scripts/tests/cache_age_policy_034_model.py new file mode 100755 index 0000000..2f15101 --- /dev/null +++ b/scripts/tests/cache_age_policy_034_model.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python3 +"""Deterministic oracle for HTTP Age / local freshness-cap algebra. +No binary execution, no claim of measured throughput. Run with Python 3 only. +""" +import json +import random +from pathlib import Path + + +def old_freshness(max_age, header_age, apparent_age, response_delay, local_limit): + age = max(header_age, apparent_age) + response_delay + return max(0, min(max_age, local_limit) - age) + + +def new_freshness(max_age, header_age, apparent_age, response_delay, local_limit): + # RFC 9111 corrected_initial_age = max(apparent_age, age_value + response_delay) + age = max(apparent_age, header_age + response_delay) + lifetime = min(max_age, age + local_limit) + return max(0, lifetime - age) + + +def run(): + cases = [ + ('user_cdn_example', 2_592_000, 1_553_483, 0, 0, 86_400), + ('user_cdn_example_7d', 2_592_000, 1_553_483, 0, 0, 604_800), + ('origin_nearly_stale', 2_592_000, 2_591_990, 0, 0, 86_400), + ('origin_stale', 2_592_000, 2_592_010, 0, 0, 86_400), + ('normal_small', 3_600, 0, 0, 0, 86_400), + ('date_is_older', 3_600, 10, 600, 2, 86_400), + ('rfc_delay_case', 3_600, 3, 10, 2, 86_400), + ] + report = {'reference': 'RFC 9111 4.2.3 (Age) and 4.2.1 (freshness lifetime)', + 'kind': 'algebra simulation; not RustProxy RPS benchmark', + 'scenarios': [], 'randomized_checks': 0, 'false_miss_cases_old': 0} + for name, max_age, age, apparent, delay, local in cases: + old = old_freshness(max_age, age, apparent, delay, local) + new = new_freshness(max_age, age, apparent, delay, local) + report['scenarios'].append({'scenario': name, 'origin_max_age_seconds': max_age, + 'received_age_seconds': age, 'apparent_age_seconds': apparent, + 'response_delay_seconds': delay, 'local_max_ttl_seconds': local, + 'old_freshness_seconds': old, 'new_freshness_seconds': new}) + rng = random.Random(0x3400) + for _ in range(100_000): + origin = rng.randrange(0, 1 << 24) + header_age = rng.randrange(0, 1 << 24) + apparent = rng.randrange(0, 1 << 24) + delay = rng.randrange(0, 300) + local = rng.randrange(0, 604_801) + corrected_age = max(apparent, header_age + delay) + new = new_freshness(origin, header_age, apparent, delay, local) + expected = min(max(0, origin - corrected_age), local) + assert new == expected, (origin, header_age, apparent, delay, local, new, expected) + assert new <= local and new <= max(0, origin - corrected_age) + old = old_freshness(origin, header_age, apparent, delay, local) + report['false_miss_cases_old'] += old == 0 < new + report['randomized_checks'] += 1 + return report + + +if __name__ == '__main__': + report = run() + print(json.dumps(report, ensure_ascii=False, indent=2)) diff --git a/scripts/tests/cache_age_transform_034_live.py b/scripts/tests/cache_age_transform_034_live.py new file mode 100755 index 0000000..b50ef00 --- /dev/null +++ b/scripts/tests/cache_age_transform_034_live.py @@ -0,0 +1,193 @@ +#!/usr/bin/env python3 +"""Loopback integration regression: transformed Age, HOT/COLD, diagnostics, isolation. + +Run after compiling: + python3 scripts/tests/cache_age_transform_034_live.py --binary target/release/rust-proxy +To reproduce the original regression with the user-supplied 0.34.0 binary: + python3 scripts/tests/cache_age_transform_034_live.py --binary /path/to/old/rust-proxy --expect-old-age-bug +No internet and no user data; test config/data/passwords are in a disposable temporary dir. +""" +import argparse +import collections +import copy +import json +import sys +import threading +import time +from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer +from pathlib import Path + +sys.path.insert(0, str(Path(__file__).resolve().parents[1] / 'performance')) +from common import Fixture, http, sha256, write_json + +BODY = b'/* test cache */\nbody { color: red; padding: 0px; }\n' +# Fixed sample from Brotli encoder, embedded to avoid Python dependency on brotli. +BROTLI_BODY = b"\x1b3\x00\xe8\x1d\x07\xee\xbe\r\xa2\xbc3'\x8cP\xe9\xad\xa0\xf2\xb2\xa7\xe4\xfa\x12\x84\xac\x0c\x1cr\xc0\xfe\xc0>\x0fR*a\x9c\x9e2\xe8\x08\xcb\x1cP\x881\xac\xdd\x88s5(\x9d\x01" +COUNTS = collections.Counter() + +class Origin(BaseHTTPRequestHandler): + def log_message(self, *_): + pass + + def do_GET(self): + path = self.path.split('?', 1)[0] + if path not in {'/aged.css', '/normal.css', '/private.css', '/no-store.css', '/other.css', '/br.css', '/aged-br.css'}: + self.send_error(404) + return + COUNTS[path] += 1 + self.send_response(200) + if path in ('/aged.css', '/aged-br.css'): + policy = 'public, max-age=2592000' + elif path == '/private.css': + policy = 'private, max-age=2592000' + elif path == '/no-store.css': + policy = 'no-store' + else: + policy = 'public, max-age=3600' + self.send_header('Cache-Control', policy) + self.send_header('Content-Type', 'text/css') + payload = BROTLI_BODY if path in ('/br.css', '/aged-br.css') else BODY + self.send_header('Content-Length', str(len(payload))) + if path in ('/br.css', '/aged-br.css'): + self.send_header('Content-Encoding', 'br') + self.send_header('ETag', '"origin-css"') + self.send_header('Last-Modified', 'Thu, 07 Jan 2016 20:04:59 GMT') + self.send_header('Vary', 'Accept-Encoding') + if path in ('/aged.css', '/aged-br.css'): + self.send_header('Age', '1553483') + self.end_headers() + self.wfile.write(payload) + + +def request(port, path, encoding='identity'): + status, headers, body = http(port, path, headers={'Accept-Encoding': encoding}) + return {'status': status, 'x_cache': headers.get('x-cache'), + 'x_cache_hits': headers.get('x-cache-hits'), 'x_cache_resident_age': headers.get('x-cache-resident-age'), + 'cache_status': headers.get('cache-status'), 'age': headers.get('age'), + 'body': body.decode('utf-8', 'replace'), 'content_length': headers.get('content-length'), + 'etag': headers.get('etag'), 'encoding': headers.get('content-encoding'), 'origin_count': COUNTS[path]} + + +def dash(rust): + status, _, body = rust.admin('/api/cache?limit=200') + assert status == 200, ('cache dashboard', status, body[:200]) + data = json.loads(body)['dashboard'] + return {'objects': [{k: row.get(k) for k in ('vhost','path','tier','transformed', + 'hits','age_seconds','resident_age_seconds','remaining_ttl_seconds')} for row in data['objects']], + 'domains': data['domains']} + + +def find(d, path): + matches = [item for item in d['objects'] if item['path'] == path and item['vhost'] == 'reverse'] + assert len(matches) == 1, (path, matches) + return matches[0] + + +def run(binary: Path, output: Path, expect_old_age_bug: bool): + outcome = {'binary_sha256': sha256(binary), 'expect_old_age_bug': expect_old_age_bug, + 'tests': [], 'passed': False} + output.mkdir(parents=True, exist_ok=True) + with Fixture(output, workers=2) as fixture: + origin = ThreadingHTTPServer(('127.0.0.1', fixture.origin_port), Origin) + thread = threading.Thread(target=origin.serve_forever, daemon=True) + thread.start() + try: + rust = fixture.rust(binary, 'cache-age-034') + rust.login() + cfg = copy.deepcopy(rust.base) + cfg['cache'] = {'enabled': True, 'max_ttl_seconds': 86_400, + 'expose_status': True, 'expose_hits': True, + 'expose_cache_status': True, 'expose_resident_age': True} + cfg['transform'] = {'enabled': True, 'css': True} + for vhost in cfg['vhosts']: + vhost['transform'] = {'enabled': True, 'css': True} + rust.apply(cfg, 'fresh-cache-transform') + for path in ('/normal.css', '/aged.css', '/br.css', '/aged-br.css', '/private.css', '/no-store.css'): + before = COUNTS[path] + encoding = 'br' if path in ('/br.css', '/aged-br.css') else 'identity' + first, second = request(rust.reverse_port, path, encoding), request(rust.reverse_port, path, encoding) + row = {'path': path, 'first': first, 'second': second, + 'origin_delta': COUNTS[path] - before} + outcome['tests'].append(row) + if path in ('/aged.css', '/aged-br.css') and expect_old_age_bug: + assert first['x_cache'] == second['x_cache'] == 'MISS', row + assert row['origin_delta'] == 2, row + elif path in ('/normal.css', '/aged.css', '/br.css', '/aged-br.css'): + assert first['x_cache'] == 'MISS' and second['x_cache'] == 'HIT', row + assert row['origin_delta'] == 1, row + assert second['cache_status'] and 'transformed' in second['cache_status'], row + assert first['etag'] == second['etag'] and first['body'] == second['body'], row + else: + assert first['x_cache'] == second['x_cache'] == 'MISS', row + print(path, first['x_cache'], second['x_cache'], 'origin+', row['origin_delta'], flush=True) + snapshot = dash(rust) + outcome['tests'].append({'dashboard': snapshot}) + assert find(snapshot, '/normal.css')['transformed'], snapshot + aged = find(snapshot, '/aged.css') + if expect_old_age_bug: + assert aged['remaining_ttl_seconds'] == 0, aged + else: + assert aged['transformed'] and aged['remaining_ttl_seconds'] >= 86_000, aged + assert aged['age_seconds'] >= 1_553_483, aged + assert aged['resident_age_seconds'] < 10, aged + aged_br = find(snapshot, '/aged-br.css') + assert aged_br['transformed'] and aged_br['remaining_ttl_seconds'] >= 86_000, aged_br + + # Operational LB tuning must not invalidate a cached representation. + before = COUNTS['/normal.css'] + cfg['vhosts'][0]['load_balancing']['keepalive'] = {'max_idle_per_host': 16} + rust.apply(cfg, 'only-backend-keepalive-changed') + normal = request(rust.reverse_port, '/normal.css') + assert normal['x_cache'] == 'HIT' and COUNTS['/normal.css'] == before + outcome['tests'].append({'keepalive_update_without_purge': normal}) + + # Diagnostics can be intentionally hidden on MISS and remain visible on HIT. + cfg['cache']['expose_only_hits'] = True + rust.apply(cfg, 'only-show-hit-headers') + before = COUNTS['/other.css'] + first, second = request(rust.reverse_port, '/other.css'), request(rust.reverse_port, '/other.css') + assert first['x_cache'] is None and second['x_cache'] == 'HIT' + assert COUNTS['/other.css'] - before == 1 + outcome['tests'].append({'only_hits': [first, second]}) + + if not expect_old_age_bug: + # Cold path on a 1-entry HOT tier: demotion and on-disk reuse. + cfg['cache'].update({'max_entries': 1, 'cold_enabled': True, 'cold_on_lru': True, + 'cold_path': 'cache/age-regression-cold'}) + cfg['cache'].pop('expose_only_hits', None) + rust.apply(cfg, 'cold-enabled-one-hot-entry') + assert request(rust.reverse_port, '/aged.css')['x_cache'] == 'MISS' + assert request(rust.reverse_port, '/aged.css')['x_cache'] == 'HIT' + assert request(rust.reverse_port, '/other.css')['x_cache'] == 'MISS' + deadline = time.monotonic() + 4 + while True: + snapshot = dash(rust) + matches = [x for x in snapshot['objects'] if x['path'] == '/aged.css' and x['tier'] == 'cold'] + if matches: + assert matches[0]['remaining_ttl_seconds'] >= 86_000, matches + break + if time.monotonic() > deadline: + raise AssertionError('aged transformed CSS never demoted to COLD: ' + str(snapshot)) + time.sleep(.05) + cold_hit = request(rust.reverse_port, '/aged.css') + assert cold_hit['x_cache'] == 'HIT' and 'transformed' in cold_hit['cache_status'], cold_hit + outcome['tests'].append({'cold': {'row': matches[0], 'hit': cold_hit}}) + outcome['passed'] = True + finally: + origin.shutdown() + origin.server_close() + write_json(output / 'cache-age-transform-result.json', outcome) + return outcome + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('--binary', type=Path, required=True) + parser.add_argument('--output', type=Path, default=Path('/tmp/rustproxy-cache-age-034-live')) + parser.add_argument('--expect-old-age-bug', action='store_true') + args = parser.parse_args() + try: + report = run(args.binary.resolve(), args.output.resolve(), args.expect_old_age_bug) + except Exception as error: + print('FAIL', type(error).__name__, str(error)[:1000], file=sys.stderr) + raise + print('PASS', len(report['tests']), 'scenarios; see', args.output / 'cache-age-transform-result.json') diff --git a/scripts/tests/cache_scope_034_static_test.py b/scripts/tests/cache_scope_034_static_test.py old mode 100644 new mode 100755 diff --git a/scripts/tests/proxy_hotpath_034_static_test.py b/scripts/tests/proxy_hotpath_034_static_test.py old mode 100644 new mode 100755 diff --git a/scripts/tests/sendfile_034_panel_browser_test.py b/scripts/tests/sendfile_034_panel_browser_test.py old mode 100644 new mode 100755 diff --git a/scripts/tests/sendfile_034_static_test.py b/scripts/tests/sendfile_034_static_test.py old mode 100644 new mode 100755 diff --git a/src/admin/web/cache-panel.js b/src/admin/web/cache-panel.js index 3fee025..29caaf3 100644 --- a/src/admin/web/cache-panel.js +++ b/src/admin/web/cache-panel.js @@ -174,7 +174,7 @@ tr.append(target); const keyTags = `${row.cache_key || "-"}${row.tags?.length ? ` · ${row.tags.join(", ")}` : ""}`; tr.append(makeCopyCell(keyTags)); - for (const value of [row.tier === "cold" ? t("cacheCold") : t("cacheHot"), fmtBytes(body), fmtBytes(storage), fmtBytes(Math.max(0, storage - body)), number(row.hits), `${number(row.age_seconds)} s`, `${number(row.remaining_ttl_seconds)} s`]) tr.append(el("td", value)); + for (const value of [row.tier === "cold" ? t("cacheCold") : t("cacheHot"), fmtBytes(body), fmtBytes(storage), fmtBytes(Math.max(0, storage - body)), number(row.hits), `${number(row.age_seconds)} s`, `${number(row.resident_age_seconds)} s`, `${number(row.remaining_ttl_seconds)} s`]) tr.append(el("td", value)); const action = el("td"), button = el("button", t("cachePurgeUrl"), "quiet"); button.type = "button"; button.addEventListener("click", () => void purgeObject(row)); action.append(button); tr.append(action); return tr; })); const bans = data.bans || []; diff --git a/src/admin/web/index.html b/src/admin/web/index.html index 72de14e..aa3c72a 100644 --- a/src/admin/web/index.html +++ b/src/admin/web/index.html @@ -1413,6 +1413,7 @@