0.34 #2
No files matched your search
@@ -5,6 +5,29 @@
|
|||||||
|
|
||||||
## 0.34.0
|
## 0.34.0
|
||||||
|
|
||||||
|
- Follow-up HOT cache path: clone response headers outside the shared store
|
||||||
|
mutex using immutable `Arc<HeaderMap>` metadata; preserve exact hit/LRU
|
||||||
|
accounting and per-response Age/transform flags. Fast-path direct no-Vary
|
||||||
|
keys and avoid per-HIT domain string allocations, inactive BAN locks and
|
||||||
|
repeated full retention sweeps (stale objects remain for revalidation).
|
||||||
|
- Add dedicated concurrent HOT hit, transformed header isolation, exact LRU,
|
||||||
|
BAN, stale-age tests and a manually ignored microbenchmark. No policy,
|
||||||
|
cache-file format or panel changes. New code remains uncompiled/unmeasured;
|
||||||
|
see docs/CACHE_HOTPATH_0.34.0.md.
|
||||||
|
|
||||||
|
- Follow-up reverse-proxy RPS revision: reuse typed upstream HTTP origin URIs,
|
||||||
|
use thread-local cryptographic nonce generation for per-request IDs,
|
||||||
|
reduce smooth-WRR member-ID clones, and share compiled health policies with probes.
|
||||||
|
- Cache backend lease once for streaming uploads instead of locking it on each
|
||||||
|
DATA frame; move access-log events directly into history when there are no
|
||||||
|
external consumers; remove repeated route attribution in forwarding.
|
||||||
|
- Retain exact per-request pool-recycle count and age limits plus independent
|
||||||
|
supervisor rotation, and keep H1/H2 protocol telemetry. No altered upstream keepalive defaults or cache query policies.
|
||||||
|
- Add source-only invariants, Rust regression cases and reproducible live
|
||||||
|
before/after/nginx benchmarking instructions. This revision has not yet been
|
||||||
|
compiled or measured for RPS; see docs/PROXY_RPS_0.34.0.md.
|
||||||
|
|
||||||
|
|
||||||
- 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.
|
- 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.
|
- 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.
|
- Expose both total HTTP Age and time resident in RustProxy HOT/COLD in the cache dashboard, with Polish/English labels.
|
||||||
|
|||||||
@@ -1,5 +1,18 @@
|
|||||||
# RustProxy 0.34.0
|
# RustProxy 0.34.0
|
||||||
|
|
||||||
|
## 0.34.0: HOT HIT critical-section follow-up (source candidate)
|
||||||
|
|
||||||
|
Immutable response headers are shared until a HIT; the mutable per-response
|
||||||
|
copy and Body are built outside the cache's shared HOT mutex. No-Vary lookups,
|
||||||
|
per-domain counters, repeated cache reasons and inactive BAN checks use
|
||||||
|
shorter paths. The existing stale-for-revalidation policy makes the previous
|
||||||
|
full HOT sweep unnecessary. Exact LRU, generation barriers, BAN, COLD,
|
||||||
|
transformation/ETag, TTL and cache bypass settings remain unchanged.
|
||||||
|
|
||||||
|
This is **uncompiled source**; do not infer network RPS or production acceptance
|
||||||
|
from source checks. See
|
||||||
|
[`docs/CACHE_HOTPATH_0.34.0.md`](docs/CACHE_HOTPATH_0.34.0.md).
|
||||||
|
|
||||||
## 0.34.0: reverse-proxy hot-path optimization revision (source candidate)
|
## 0.34.0: reverse-proxy hot-path optimization revision (source candidate)
|
||||||
|
|
||||||
This revision retains the **0.34.0** version and all prior scoped-cache,
|
This revision retains the **0.34.0** version and all prior scoped-cache,
|
||||||
|
|||||||
+84
-82
@@ -2,7 +2,7 @@
|
|||||||
4140a2956264b44f259e6a37fc00ba02097bbe68b09296e04d3d243c1287129b .env.example
|
4140a2956264b44f259e6a37fc00ba02097bbe68b09296e04d3d243c1287129b .env.example
|
||||||
9e6356475bf587091bab72246ec9e325b498f7e48a6220e9a18baa50d0a385a6 .gitignore
|
9e6356475bf587091bab72246ec9e325b498f7e48a6220e9a18baa50d0a385a6 .gitignore
|
||||||
46bab1d2c2d6e0a80d57a6b232b1ba4c220884b95cd45ddccbafce2aa160cddb AGENTS.md
|
46bab1d2c2d6e0a80d57a6b232b1ba4c220884b95cd45ddccbafce2aa160cddb AGENTS.md
|
||||||
4e0a7371f060063a6a73ae1c1a2faba2de8d227118be2406c88ca432c90305eb CHANGELOG.md
|
688f666a676d77847aade6ef97fd82a565b88c9b314050ddeb313a1b3ec4663a CHANGELOG.md
|
||||||
ca201e3cd3f9842eae0006d0b40a0a72bcd3d4da6e4e5ecaf200d1b9a1390db2 Cargo.lock
|
ca201e3cd3f9842eae0006d0b40a0a72bcd3d4da6e4e5ecaf200d1b9a1390db2 Cargo.lock
|
||||||
fec5f1bae9a59ef1fabd27c5e45d31448dd8f811736eebfa8826b3806a7e3349 Cargo.toml
|
fec5f1bae9a59ef1fabd27c5e45d31448dd8f811736eebfa8826b3806a7e3349 Cargo.toml
|
||||||
25c7f3c8162cbf5cc156439774118a81dae9fdc52b611ec7e40c230fc99a772c Dockerfile
|
25c7f3c8162cbf5cc156439774118a81dae9fdc52b611ec7e40c230fc99a772c Dockerfile
|
||||||
@@ -56,6 +56,7 @@ e68d5a5cf0991de9308f78afb0264e02979f7463a5f395eb7a6e9ec2bd3a3d54 docs/PHP_FPM.m
|
|||||||
bc068a176056f5ea4d3b637071e644ed58a2140494c233ef22aa66e9700e3299 docs/PHP_FPM_ISOLATION.md
|
bc068a176056f5ea4d3b637071e644ed58a2140494c233ef22aa66e9700e3299 docs/PHP_FPM_ISOLATION.md
|
||||||
ad6e3f003b820a4f45e30e39577d120a69d167c70910bda4891971759458c3dd docs/PROMETHEUS.md
|
ad6e3f003b820a4f45e30e39577d120a69d167c70910bda4891971759458c3dd docs/PROMETHEUS.md
|
||||||
deea89aed410c0619bdbdb12437edc7aff9dca2fec7fdc059e918c649fc36b51 docs/PROXY_HOTPATH_0.34.0.md
|
deea89aed410c0619bdbdb12437edc7aff9dca2fec7fdc059e918c649fc36b51 docs/PROXY_HOTPATH_0.34.0.md
|
||||||
|
f92715fc95ca3b837ff8352e3c899569cdb0f72bcb45c09b050cf1f1ff7ccfe5 docs/PROXY_RPS_0.34.0.md
|
||||||
887d1fdcc3b546b024afcd18b1716b8e3a74a3800012bf4bda7a122d2eabe233 docs/README.md
|
887d1fdcc3b546b024afcd18b1716b8e3a74a3800012bf4bda7a122d2eabe233 docs/README.md
|
||||||
6e46a137b9c88dac8cb9e3fdca877430092392de9913d746278dbff8652460c2 docs/REDIRECTS.md
|
6e46a137b9c88dac8cb9e3fdca877430092392de9913d746278dbff8652460c2 docs/REDIRECTS.md
|
||||||
0dfd0d431c5aedc67abac1ce5de040ffa790ec9578fd7d6f91a987c333d73358 docs/REFERENCES.md
|
0dfd0d431c5aedc67abac1ce5de040ffa790ec9578fd7d6f91a987c333d73358 docs/REFERENCES.md
|
||||||
@@ -69,7 +70,7 @@ ec7e32fd19e6ba6ed1732f1f3dd92ac0860609e8c0bbd3c1998840cdfb24bf54 docs/SECURITY.
|
|||||||
4dcf3243a13d9ae1827b5cefdbb9e27bd6310321c50d4d5934527d44437df6ef docs/SETTINGS.md
|
4dcf3243a13d9ae1827b5cefdbb9e27bd6310321c50d4d5934527d44437df6ef docs/SETTINGS.md
|
||||||
8fc112cb45a2f35ef5b0dd4371aa6f43aca4df85db62c6ae02e56d74a3b702ae docs/STREAMS.md
|
8fc112cb45a2f35ef5b0dd4371aa6f43aca4df85db62c6ae02e56d74a3b702ae docs/STREAMS.md
|
||||||
95148bfa1d2f8ff52b591c9acefc6c8992dadc4ebda43a195101d9b31d67a576 docs/TEST_REPORT.md
|
95148bfa1d2f8ff52b591c9acefc6c8992dadc4ebda43a195101d9b31d67a576 docs/TEST_REPORT.md
|
||||||
4c82db7fab8c8fe8cd1508fbb85751b7f72071edd913ee7def4a9ffde8efa13e docs/TEST_REPORT_0.34.0.md
|
ec1bf1690edc056068cbdec7244e3a98a2da2da953e0b4399301d76585a69be6 docs/TEST_REPORT_0.34.0.md
|
||||||
cfb452d8496839e832b5fbacdd4e52525b0ecc3112fbb62340c1e580bd5c1717 docs/TODO.md
|
cfb452d8496839e832b5fbacdd4e52525b0ecc3112fbb62340c1e580bd5c1717 docs/TODO.md
|
||||||
751c9b13b47d0959a8575d6e82bdecba988b950a374ba0b084fbba08b4b65ebe docs/TRANSFORM.md
|
751c9b13b47d0959a8575d6e82bdecba988b950a374ba0b084fbba08b4b65ebe docs/TRANSFORM.md
|
||||||
fe3ec6ca16ff933239c12dacf39dd7b45717c0551a8b9f6ce601bf78136c9e37 docs/TRANSPORT.md
|
fe3ec6ca16ff933239c12dacf39dd7b45717c0551a8b9f6ce601bf78136c9e37 docs/TRANSPORT.md
|
||||||
@@ -129,7 +130,7 @@ a641bd35400c56f3b68b0a92e97b602d06090f03972ca8f01fa744e90dd97403 scripts/deploy
|
|||||||
2cc658faaa610b21b48942c59b955525539ad4503fd60f2a49c7e626a22faaff scripts/migration/migrate_npm.py
|
2cc658faaa610b21b48942c59b955525539ad4503fd60f2a49c7e626a22faaff scripts/migration/migrate_npm.py
|
||||||
a459d95bbb0076f33ade8b273b813308167f9d8d45242b309a2d18320ca0093c scripts/migration/migrate_npm_api.py
|
a459d95bbb0076f33ade8b273b813308167f9d8d45242b309a2d18320ca0093c scripts/migration/migrate_npm_api.py
|
||||||
31ccad3ec3c880119f3b7002f0c6652f8b43634edad8ab3763cb0e4497d0bb1f scripts/migration/migrate_npm_core.py
|
31ccad3ec3c880119f3b7002f0c6652f8b43634edad8ab3763cb0e4497d0bb1f scripts/migration/migrate_npm_core.py
|
||||||
e4fd7fa94d661d4610d7d86fcdeaae9d6deb220e95b8d3bbd67ec15fbd017ccb scripts/performance/README.md
|
c79b709fb6f806a772464b709e652e6dfcf498b850281df5e1c594c98392cb23 scripts/performance/README.md
|
||||||
0380406a059ee9ec27473f8a46435f638f73a6dc729382ae1561c08dbf7ccb53 scripts/performance/benchmark.py
|
0380406a059ee9ec27473f8a46435f638f73a6dc729382ae1561c08dbf7ccb53 scripts/performance/benchmark.py
|
||||||
9ac220163256e08513597c397c016a48345b114d7876b439259cc310b36c83fc scripts/performance/checks_cache.py
|
9ac220163256e08513597c397c016a48345b114d7876b439259cc310b36c83fc scripts/performance/checks_cache.py
|
||||||
f09125d081d0eed9a44fdca75de14e6bbf09dcb00fe1f027ba2270f89e3ff192 scripts/performance/checks_policy.py
|
f09125d081d0eed9a44fdca75de14e6bbf09dcb00fe1f027ba2270f89e3ff192 scripts/performance/checks_policy.py
|
||||||
@@ -157,8 +158,8 @@ e69813fb1d3a4cdcfb7243964cc323fc21a603087bf2e84188fa42b9d3cee4b5 scripts/runtim
|
|||||||
046b4282550f5cb4e53906665c91c7442be70fc68fd0743466fd832582f7c979 scripts/test_stream_tcp.py
|
046b4282550f5cb4e53906665c91c7442be70fc68fd0743466fd832582f7c979 scripts/test_stream_tcp.py
|
||||||
f0b48ec0cc4411755cc0b4128eebce710375afa99344cb76198cf31074f8eb63 scripts/test_stream_udp.py
|
f0b48ec0cc4411755cc0b4128eebce710375afa99344cb76198cf31074f8eb63 scripts/test_stream_udp.py
|
||||||
fafd577ccbb58485c47de35fc125e5c64a3a7628ae40d01d4cd924fce2f414db scripts/tests/cache_age_policy_034_model.py
|
fafd577ccbb58485c47de35fc125e5c64a3a7628ae40d01d4cd924fce2f414db scripts/tests/cache_age_policy_034_model.py
|
||||||
972d79127309071a15e231ca45d24c9a8347c25115d0ec4fd91a74ca56b3f665 scripts/tests/cache_age_transform_034_live.py
|
b75a381d1b41bfb2ea7d2ce09728249b5e1465f76d57e2c3f151af72a5ae4d03 scripts/tests/cache_age_transform_034_live.py
|
||||||
955c150f8d0490069cb14b659d4fb4e0b529a28b87c27bd6697935c23e7ef192 scripts/tests/cache_scope_034_static_test.py
|
6cb79535f742d1a41685f486688dc2f1330ea362e3da1a15d4fa32561094282f scripts/tests/cache_scope_034_static_test.py
|
||||||
efb7a1fde2c74f30cd4a1abb88ae07c1cac7378bb33685dd09d52bb30849daac scripts/tests/dashboard_chart_headers_0335_browser_test.py
|
efb7a1fde2c74f30cd4a1abb88ae07c1cac7378bb33685dd09d52bb30849daac scripts/tests/dashboard_chart_headers_0335_browser_test.py
|
||||||
eb2c9e5c968938b6fbe4675b547ba1f537519878b9095e1fea133f4d83f96fc8 scripts/tests/dashboard_chart_typography_0337_browser_test.py
|
eb2c9e5c968938b6fbe4675b547ba1f537519878b9095e1fea133f4d83f96fc8 scripts/tests/dashboard_chart_typography_0337_browser_test.py
|
||||||
6a908fd434d2a8a80adfd06a66d4b83c4174e448d453a8c10b1812475d036677 scripts/tests/dashboard_chart_width_0333_browser_test.py
|
6a908fd434d2a8a80adfd06a66d4b83c4174e448d453a8c10b1812475d036677 scripts/tests/dashboard_chart_width_0333_browser_test.py
|
||||||
@@ -178,6 +179,7 @@ fa42ec0475e4398d647b3c094309b4332cd2b5649db223cae0b8e821d6b44a28 scripts/tests/
|
|||||||
b0136544af717b75df2cb107900ea65c3f945fdd0040369dbb93919008fb954c scripts/tests/panel_html.py
|
b0136544af717b75df2cb107900ea65c3f945fdd0040369dbb93919008fb954c scripts/tests/panel_html.py
|
||||||
8d1903e2b17b3d59cd0a5bec3e298e468b3d88ed2dda8b724239cc45d8353c59 scripts/tests/progressbar_0332_browser_test.py
|
8d1903e2b17b3d59cd0a5bec3e298e468b3d88ed2dda8b724239cc45d8353c59 scripts/tests/progressbar_0332_browser_test.py
|
||||||
f94612eaefb4098e1a4efc0d970ce52a656db239aaa0a012df47567527bf3708 scripts/tests/proxy_hotpath_034_static_test.py
|
f94612eaefb4098e1a4efc0d970ce52a656db239aaa0a012df47567527bf3708 scripts/tests/proxy_hotpath_034_static_test.py
|
||||||
|
9d28d523aeed722f6ed9217d6eb30530d4fb103e036983d680909a9011dba8de scripts/tests/rps_hotpath_034_static_test.py
|
||||||
5be5cdc60324f4f0f6638640000b888a5babb0a9bbf29511c824a0ba38878c2a scripts/tests/sendfile_034_panel_browser_test.py
|
5be5cdc60324f4f0f6638640000b888a5babb0a9bbf29511c824a0ba38878c2a scripts/tests/sendfile_034_panel_browser_test.py
|
||||||
978789bfe89d43034dfebddba49b9b17daedb1be031732734f95375e56c78306 scripts/tests/sendfile_034_static_test.py
|
978789bfe89d43034dfebddba49b9b17daedb1be031732734f95375e56c78306 scripts/tests/sendfile_034_static_test.py
|
||||||
1bb99b148d0297235b707f16865ca077329246fc19ecbb20a143bdeb56a23f37 scripts/tests/sidebar_nav_0333_browser_test.py
|
1bb99b148d0297235b707f16865ca077329246fc19ecbb20a143bdeb56a23f37 scripts/tests/sidebar_nav_0333_browser_test.py
|
||||||
@@ -191,26 +193,26 @@ f0a2e3daa0a49aac54723cb5a281360e49a97c076281372c5cca2a85e096c02c scripts/tests/
|
|||||||
f55efa99245bbdbc98fe3202e52952d224ac3200612561580d52f6e251810049 scripts/tests/web_server_0330_ui_test.py
|
f55efa99245bbdbc98fe3202e52952d224ac3200612561580d52f6e251810049 scripts/tests/web_server_0330_ui_test.py
|
||||||
0dd1cef06a1c3e1546e2fb9b085bf369dfbed02107b9ab01b4fb4f3b894099c0 scripts/tests/web_server_0334_browser_test.py
|
0dd1cef06a1c3e1546e2fb9b085bf369dfbed02107b9ab01b4fb4f3b894099c0 scripts/tests/web_server_0334_browser_test.py
|
||||||
22e880e98c7b9d700c7a4c02b9b1d543e5dbd1f4ecdca42813a1083165b32a19 scripts/version.py
|
22e880e98c7b9d700c7a4c02b9b1d543e5dbd1f4ecdca42813a1083165b32a19 scripts/version.py
|
||||||
55485a513e8c4da2a58daa7abcb15b32ed408a5fc062cf23599fb83d16b90cfe src/acl.rs
|
|
||||||
63efab1e95d41134fc30cc57320c32810bbae9f81a640bdb24b1be2059e63d8a src/acl/dynamic.rs
|
|
||||||
4803e44de39b872a5b3b55f9ca9e81c066ba52cb8f6adb879fd57c5f94b93e89 src/acl/dynamic/tests.rs
|
4803e44de39b872a5b3b55f9ca9e81c066ba52cb8f6adb879fd57c5f94b93e89 src/acl/dynamic/tests.rs
|
||||||
|
63efab1e95d41134fc30cc57320c32810bbae9f81a640bdb24b1be2059e63d8a src/acl/dynamic.rs
|
||||||
a22e5ea6381a1eacafe650be0f5cd6e653773e31f6491a562fe0459a309fb7cc src/acl/tests.rs
|
a22e5ea6381a1eacafe650be0f5cd6e653773e31f6491a562fe0459a309fb7cc src/acl/tests.rs
|
||||||
6f5d3137bf24451da05c1db9f0f9e2a451305db17b6bc2590815ad54a6511829 src/acme.rs
|
55485a513e8c4da2a58daa7abcb15b32ed408a5fc062cf23599fb83d16b90cfe src/acl.rs
|
||||||
587097620b2f25ce7c6f59f907b47660184b095e3040c7615e74509a82e7cdd8 src/acme/jobs.rs
|
587097620b2f25ce7c6f59f907b47660184b095e3040c7615e74509a82e7cdd8 src/acme/jobs.rs
|
||||||
3f158f46e80b403b658b4e9b1e3710e38c70e47b2d476b8223d9c394ffeeba95 src/acme/model.rs
|
3f158f46e80b403b658b4e9b1e3710e38c70e47b2d476b8223d9c394ffeeba95 src/acme/model.rs
|
||||||
c5334de6c732d76b2bea7bfc17b3ac305a250bbaad31a5420d6a7d7abb200449 src/acme/providers.rs
|
|
||||||
d1dcb7bdfb7cfdc9c3b88cfb6908201c58532bc888744a13f45853079f214659 src/acme/providers/tests.rs
|
d1dcb7bdfb7cfdc9c3b88cfb6908201c58532bc888744a13f45853079f214659 src/acme/providers/tests.rs
|
||||||
|
c5334de6c732d76b2bea7bfc17b3ac305a250bbaad31a5420d6a7d7abb200449 src/acme/providers.rs
|
||||||
29ff0647417b0f1d50a4cc075ab51afecff9ddf47db3eb7948d51db5a38f33f3 src/acme/runtime_bootstrap.rs
|
29ff0647417b0f1d50a4cc075ab51afecff9ddf47db3eb7948d51db5a38f33f3 src/acme/runtime_bootstrap.rs
|
||||||
87f64198770ae026c03a242fa542db2590ca734b02e756f1e5c28d66236f753a src/acme/runtime_env.rs
|
87f64198770ae026c03a242fa542db2590ca734b02e756f1e5c28d66236f753a src/acme/runtime_env.rs
|
||||||
f8075a5ef9ae5651d72a33ac0f0fd5b44ad0ae30f6e2d2318412177e0ed837f5 src/acme/runtime_versions.rs
|
f8075a5ef9ae5651d72a33ac0f0fd5b44ad0ae30f6e2d2318412177e0ed837f5 src/acme/runtime_versions.rs
|
||||||
e38331a1b186b49fe9d04051de52b603e1fa028def37e4e2f52e386b4d7b29ac src/acme/tests.rs
|
e38331a1b186b49fe9d04051de52b603e1fa028def37e4e2f52e386b4d7b29ac src/acme/tests.rs
|
||||||
|
6f5d3137bf24451da05c1db9f0f9e2a451305db17b6bc2590815ad54a6511829 src/acme.rs
|
||||||
b6f38f3fd75d6685bbc882ed1077a38bf495cfcf01c397f69ed9b98be68b446f src/admin/access.rs
|
b6f38f3fd75d6685bbc882ed1077a38bf495cfcf01c397f69ed9b98be68b446f src/admin/access.rs
|
||||||
b4a2a068acfa1143b0032b9cd072c19cf3fdda2580f0b932d11d6368cd2ab3ad src/admin/certificate_api.rs
|
b4a2a068acfa1143b0032b9cd072c19cf3fdda2580f0b932d11d6368cd2ab3ad src/admin/certificate_api.rs
|
||||||
51f46a2cb3167c4e3a784dfbb59b8fe0e9d5d3d51365b26699498e31d0afb6a9 src/admin/certificates.rs
|
51f46a2cb3167c4e3a784dfbb59b8fe0e9d5d3d51365b26699498e31d0afb6a9 src/admin/certificates.rs
|
||||||
b5f6d49f1add583cfc8cd4aa36ffe4db56dac4de3b151fe8239fe42f507019cc src/admin/dashboard_presets.rs
|
b5f6d49f1add583cfc8cd4aa36ffe4db56dac4de3b151fe8239fe42f507019cc src/admin/dashboard_presets.rs
|
||||||
5e150d4ef0413a2f92db5b6631669933b84d4b4796633d01476c4b39188cd05c src/admin/documentation.rs
|
|
||||||
958546c43c05bf4bed8121b24db3b3096f9243f3c56a71e1762592b755684013 src/admin/documentation/documents.rs
|
958546c43c05bf4bed8121b24db3b3096f9243f3c56a71e1762592b755684013 src/admin/documentation/documents.rs
|
||||||
67b901485d5858d5b5bf78a6260035db32241531d99481754c3533fdf404facb src/admin/documentation/tests.rs
|
67b901485d5858d5b5bf78a6260035db32241531d99481754c3533fdf404facb src/admin/documentation/tests.rs
|
||||||
|
5e150d4ef0413a2f92db5b6631669933b84d4b4796633d01476c4b39188cd05c src/admin/documentation.rs
|
||||||
1ce779b84aa8f47bdb3c34f83593c1f2f06d2235f0319847096cfcd035434168 src/admin/file_log_search.rs
|
1ce779b84aa8f47bdb3c34f83593c1f2f06d2235f0319847096cfcd035434168 src/admin/file_log_search.rs
|
||||||
ab18acf6fb4ac86fb22635b9219a12dac76d24952c8f15538486267a9b4b7855 src/admin/file_logs.rs
|
ab18acf6fb4ac86fb22635b9219a12dac76d24952c8f15538486267a9b4b7855 src/admin/file_logs.rs
|
||||||
c6b552cd5acd9e743c28b1a5564420c214c619fe891ab0561b7d4499aae8d6c0 src/admin/file_logs_io.rs
|
c6b552cd5acd9e743c28b1a5564420c214c619fe891ab0561b7d4499aae8d6c0 src/admin/file_logs_io.rs
|
||||||
@@ -224,8 +226,8 @@ d9120f7dc61d27621c5ac27ea49815dc7945c44d5b99d208da503818c198f649 src/admin/oper
|
|||||||
92b3e05f04711d8001b56816405859631d9e917868e15be965c7e76ef4ddef99 src/admin/preferences.rs
|
92b3e05f04711d8001b56816405859631d9e917868e15be965c7e76ef4ddef99 src/admin/preferences.rs
|
||||||
4a5cb4c3a3aa8b9a519020854506ce4be5e688a6c4298260322ae641dded7fe9 src/admin/preferences_columns.rs
|
4a5cb4c3a3aa8b9a519020854506ce4be5e688a6c4298260322ae641dded7fe9 src/admin/preferences_columns.rs
|
||||||
9a3f13e2477769ae680c03d63336880c3b7b7d5aba4a91e44390a976608b9b1d src/admin/preferences_tests.rs
|
9a3f13e2477769ae680c03d63336880c3b7b7d5aba4a91e44390a976608b9b1d src/admin/preferences_tests.rs
|
||||||
4a7a2017ba57c9e7a8b29e73764d439f6d03653403909ef198ded8c48d152784 src/admin/public.rs
|
|
||||||
7a00e4ab943f74d2b1bdcbfab7f9cd3f584e9f59536b4aca6c4c31f5f5508d12 src/admin/public/tests.rs
|
7a00e4ab943f74d2b1bdcbfab7f9cd3f584e9f59536b4aca6c4c31f5f5508d12 src/admin/public/tests.rs
|
||||||
|
4a7a2017ba57c9e7a8b29e73764d439f6d03653403909ef198ded8c48d152784 src/admin/public.rs
|
||||||
9926827131254677a848c178c80850b3ca1993c05b4bf913687dc0c7992ad048 src/admin/refresh_preferences.rs
|
9926827131254677a848c178c80850b3ca1993c05b4bf913687dc0c7992ad048 src/admin/refresh_preferences.rs
|
||||||
daef5e663c1bc99a22b3b8fa4481ae5e4916b91db132c104bc050f51b1fdf77f src/admin/router.rs
|
daef5e663c1bc99a22b3b8fa4481ae5e4916b91db132c104bc050f51b1fdf77f src/admin/router.rs
|
||||||
a40adfbaa908da3ea726d7aa3d45394a70a6a55b6fc0063270ec4d2a2f2026a3 src/admin/session.rs
|
a40adfbaa908da3ea726d7aa3d45394a70a6a55b6fc0063270ec4d2a2f2026a3 src/admin/session.rs
|
||||||
@@ -302,45 +304,44 @@ b3239e67901f1796d7a974ade0796f2e3590ff8064628a5629b78c7f6ce2f32e src/admin/web/
|
|||||||
bb93e2017f40e3a45ff7f4ca92e4188bb464f432704b6d2c39da9d9621b7984c src/admin/web/vhosts/render.js
|
bb93e2017f40e3a45ff7f4ca92e4188bb464f432704b6d2c39da9d9621b7984c src/admin/web/vhosts/render.js
|
||||||
4dfdeb7c73c2775eacaca65fd8ef1dc80b275421b15522d319d338f5b96288cc src/admin/web/web-server-profiles.js
|
4dfdeb7c73c2775eacaca65fd8ef1dc80b275421b15522d319d338f5b96288cc src/admin/web/web-server-profiles.js
|
||||||
fd476445a88eb40270e706814eee50cbfbba4069a26dd843c095367e55a147a1 src/admin/web/web-server.js
|
fd476445a88eb40270e706814eee50cbfbba4069a26dd843c095367e55a147a1 src/admin/web/web-server.js
|
||||||
53237ae8b08d261ce21e0aa6fd225bf4f3bb17a37a80529e2a4039d45b13f7c5 src/auth/files.rs
|
|
||||||
b2f948bcc3dbd24952c7b1b02d41d06757f49f0c38a78caf51f8f8a687d8480d src/auth/files/tests.rs
|
b2f948bcc3dbd24952c7b1b02d41d06757f49f0c38a78caf51f8f8a687d8480d src/auth/files/tests.rs
|
||||||
|
53237ae8b08d261ce21e0aa6fd225bf4f3bb17a37a80529e2a4039d45b13f7c5 src/auth/files.rs
|
||||||
775178ee5781e64574bdd7c1fb7d64e7e283977fbd9c98c99896532a7f1df612 src/auth/mod.rs
|
775178ee5781e64574bdd7c1fb7d64e7e283977fbd9c98c99896532a7f1df612 src/auth/mod.rs
|
||||||
c96a87e82ff0c1c9ce3d0cd5135903bb53af78d1c4fb6ebfe5fea503bf5644ea src/auth/store.rs
|
c96a87e82ff0c1c9ce3d0cd5135903bb53af78d1c4fb6ebfe5fea503bf5644ea src/auth/store.rs
|
||||||
745226cabb007819370fc6aa680995a03a8a13fa057dacfab0fcc21d0c43bbe4 src/auth/tests.rs
|
745226cabb007819370fc6aa680995a03a8a13fa057dacfab0fcc21d0c43bbe4 src/auth/tests.rs
|
||||||
09c3a622a7d2169e49e3369ea5f0f816eab2f717eaf1675c625d518c8f34d367 src/backup.rs
|
|
||||||
76aa2afe9e7302be39b3512f30d0448d9134300f8ae930d64ada40cf3ad4a8a3 src/backup/archive.rs
|
76aa2afe9e7302be39b3512f30d0448d9134300f8ae930d64ada40cf3ad4a8a3 src/backup/archive.rs
|
||||||
732cd4f9ed38ae69f8bbae61b1db8baaa6f86b07ca21c41f24a206a30f0a96fc src/backup/ownership.rs
|
732cd4f9ed38ae69f8bbae61b1db8baaa6f86b07ca21c41f24a206a30f0a96fc src/backup/ownership.rs
|
||||||
076350506215faec3cfe7d9de4e60baf29672cc22a41eabe601dcc510c257799 src/backup/snapshot.rs
|
076350506215faec3cfe7d9de4e60baf29672cc22a41eabe601dcc510c257799 src/backup/snapshot.rs
|
||||||
5c19490d834d9971166b6b784a75b081bb95fd50c8c634ef3c87924dfffd4a19 src/backup/tests.rs
|
5c19490d834d9971166b6b784a75b081bb95fd50c8c634ef3c87924dfffd4a19 src/backup/tests.rs
|
||||||
f5afae218f3a6f91bc2f1f5a90094630ce5b7ca574de61807b5a317b13937ec2 src/backup/validation.rs
|
f5afae218f3a6f91bc2f1f5a90094630ce5b7ca574de61807b5a317b13937ec2 src/backup/validation.rs
|
||||||
426a946b2c9e244f09f6cbc5f9664b8ad0737529a9bb5a3d549d27196a1f8043 src/balance.rs
|
09c3a622a7d2169e49e3369ea5f0f816eab2f717eaf1675c625d518c8f34d367 src/backup.rs
|
||||||
ca1e03b56a872dca37ed9d05ead41c1538a808e80b09fb9494823c443cd51c61 src/balance/health.rs
|
ca1e03b56a872dca37ed9d05ead41c1538a808e80b09fb9494823c443cd51c61 src/balance/health.rs
|
||||||
59d90e709bfc2be6cd48576f1c1d222891523853a46f2561f0562d74d01f60a5 src/balance/lease_runtime.rs
|
109c55f9af8918d4f314f0796e19de06f3129eefee3ef405770b99fc368f2aee src/balance/lease_runtime.rs
|
||||||
554b730c39a935b7da46bfb76b474b99cee07f8c482cb0490f2cf81ba7a51cf2 src/balance/model.rs
|
554b730c39a935b7da46bfb76b474b99cee07f8c482cb0490f2cf81ba7a51cf2 src/balance/model.rs
|
||||||
9a10649c02eeb2c05e0ca520ef6ab701f79d46591190b4432977c2d5dbc6d7f5 src/balance/pool_core.rs
|
8550e5d64aa6fee442cea3e8e243fc4cfc1e8aa39726bc5cc6b2afa9307e3d05 src/balance/pool_core.rs
|
||||||
477132dd381e23f1be197c32ff58a0925f41d3e6aa63fe77c10973cefb2b76f6 src/balance/pool_selection.rs
|
477132dd381e23f1be197c32ff58a0925f41d3e6aa63fe77c10973cefb2b76f6 src/balance/pool_selection.rs
|
||||||
8abb6048303ee8c022546a528d5693167766e7450efd8e20f37ec6fd0fa9ef5e src/balance/pool_view.rs
|
8abb6048303ee8c022546a528d5693167766e7450efd8e20f37ec6fd0fa9ef5e src/balance/pool_view.rs
|
||||||
842318f21a919055522f8bd9dae67bf4ec1c8c32dc52314cc048ba1d54a0b379 src/balance/tests.rs
|
842318f21a919055522f8bd9dae67bf4ec1c8c32dc52314cc048ba1d54a0b379 src/balance/tests.rs
|
||||||
5049d2bd01a9c866f3bad2288d8d594df96bba6045dfe15cd22b4173562b7388 src/basic_auth.rs
|
426a946b2c9e244f09f6cbc5f9664b8ad0737529a9bb5a3d549d27196a1f8043 src/balance.rs
|
||||||
9a8858b7ff461a4d961ba701ca3ed6eaec15c3f7f05eef8e0e30edc63617605a src/basic_auth/tests.rs
|
9a8858b7ff461a4d961ba701ca3ed6eaec15c3f7f05eef8e0e30edc63617605a src/basic_auth/tests.rs
|
||||||
7def03ace07dc38a4806277d75b6ce673d33ddaaf1c4855fa0a3372be1cf9489 src/cache/cold.rs
|
5049d2bd01a9c866f3bad2288d8d594df96bba6045dfe15cd22b4173562b7388 src/basic_auth.rs
|
||||||
a9eeb93519aae2de7a1282296ced91d2eb8307cc966f8fbf6085af0fd21b0ad2 src/cache/cold/cleanup.rs
|
a9eeb93519aae2de7a1282296ced91d2eb8307cc966f8fbf6085af0fd21b0ad2 src/cache/cold/cleanup.rs
|
||||||
8354ae90c1a0857773a0c6d79427925e0115d94ccfafb809ccc1ebf4ef10f9b9 src/cache/cold/demotion.rs
|
8354ae90c1a0857773a0c6d79427925e0115d94ccfafb809ccc1ebf4ef10f9b9 src/cache/cold/demotion.rs
|
||||||
2eaba3261da2a547e9af91330319a3abd3a8ad8b5b44a337a84040720209017d src/cache/cold/startup.rs
|
2eaba3261da2a547e9af91330319a3abd3a8ad8b5b44a337a84040720209017d src/cache/cold/startup.rs
|
||||||
e7c7fd71727d542c2df3e03a4a1cba9d839c516963f66bbfde1c29ec81053500 src/cache/cold/worker.rs
|
e7c7fd71727d542c2df3e03a4a1cba9d839c516963f66bbfde1c29ec81053500 src/cache/cold/worker.rs
|
||||||
|
7def03ace07dc38a4806277d75b6ce673d33ddaaf1c4855fa0a3372be1cf9489 src/cache/cold.rs
|
||||||
d51fa4f320be56c572f767617428c3f3838543cb0eeb7d1f8ae791e1a1ce9a71 src/cache/collapse.rs
|
d51fa4f320be56c572f767617428c3f3838543cb0eeb7d1f8ae791e1a1ce9a71 src/cache/collapse.rs
|
||||||
7e8741bc21e5ca75f3bf8c5e57c59b6814dc1e5e2e0548963fe35089256772bb src/cache/dashboard.rs
|
7e8741bc21e5ca75f3bf8c5e57c59b6814dc1e5e2e0548963fe35089256772bb src/cache/dashboard.rs
|
||||||
780c2654c67dbe176d8310678e6deec8022bcebfd85b95df7262069ed41f57b1 src/cache/fill.rs
|
780c2654c67dbe176d8310678e6deec8022bcebfd85b95df7262069ed41f57b1 src/cache/fill.rs
|
||||||
675d18afb53f25c56cba49bbb431fa39ecd9d7bdd192c7b39b0698225de7a2a2 src/cache/invalidation.rs
|
|
||||||
c1357a13658e1ed5158084d3a41ba9ea906512774a5863ce9c56cb508d3fa6c8 src/cache/invalidation/ban.rs
|
c1357a13658e1ed5158084d3a41ba9ea906512774a5863ce9c56cb508d3fa6c8 src/cache/invalidation/ban.rs
|
||||||
0cc31d8e70fb3774c4ce3713b94ed79c184a8d8f0d38ce66a97724410733e17e src/cache/invalidation/invalidate.rs
|
0cc31d8e70fb3774c4ce3713b94ed79c184a8d8f0d38ce66a97724410733e17e src/cache/invalidation/invalidate.rs
|
||||||
|
675d18afb53f25c56cba49bbb431fa39ecd9d7bdd192c7b39b0698225de7a2a2 src/cache/invalidation.rs
|
||||||
373031e18d0c23d006a31822ef977015c0263637e3da70c1442407f7bfed1033 src/cache/lifecycle.rs
|
373031e18d0c23d006a31822ef977015c0263637e3da70c1442407f7bfed1033 src/cache/lifecycle.rs
|
||||||
bd831807ca4720b3a41a6ea1d9a6c0ed2d935225e2dacbd9313be064f2e4a20e src/cache/lookup.rs
|
|
||||||
5aa0d9ae53f0350f5cfc4d1694a6faf9eea893460d421344d3bc5d1c4ce66529 src/cache/lookup/hot.rs
|
5aa0d9ae53f0350f5cfc4d1694a6faf9eea893460d421344d3bc5d1c4ce66529 src/cache/lookup/hot.rs
|
||||||
1779abcee77600c13050a2882f896a5b35625b1ae53737c2554179492ce0e40d src/cache/lookup/insert.rs
|
1779abcee77600c13050a2882f896a5b35625b1ae53737c2554179492ce0e40d src/cache/lookup/insert.rs
|
||||||
107a589974b9689009a9bbf088818dfaec71cd1aab8676bbc6d0118359a54a31 src/cache/lookup/tiered.rs
|
107a589974b9689009a9bbf088818dfaec71cd1aab8676bbc6d0118359a54a31 src/cache/lookup/tiered.rs
|
||||||
|
bd831807ca4720b3a41a6ea1d9a6c0ed2d935225e2dacbd9313be064f2e4a20e src/cache/lookup.rs
|
||||||
58c03fde09e5eab40968679793b364f4f1cf5fd832bd79ebcdc92bb23871ad82 src/cache/mod.rs
|
58c03fde09e5eab40968679793b364f4f1cf5fd832bd79ebcdc92bb23871ad82 src/cache/mod.rs
|
||||||
0c8b0d550e94d4474dcdf991aa0340228dc5f2f904f39350e6e666a16f16fe87 src/cache/model.rs
|
|
||||||
875116e319c5bb9d281817fed626a94e468e9e3305f21dac99d3f2535e2fb157 src/cache/model/cache.rs
|
875116e319c5bb9d281817fed626a94e468e9e3305f21dac99d3f2535e2fb157 src/cache/model/cache.rs
|
||||||
0ec4f6d0adea1ed80a3ca17c68c9c85502491da2904d9d690b4169ab9b025b21 src/cache/model/cold_metadata.rs
|
0ec4f6d0adea1ed80a3ca17c68c9c85502491da2904d9d690b4169ab9b025b21 src/cache/model/cold_metadata.rs
|
||||||
29bfce96b2ffd102d9c848c7b717a45fedb9aa44511f62f7a1f28a53dafd063a src/cache/model/entry.rs
|
29bfce96b2ffd102d9c848c7b717a45fedb9aa44511f62f7a1f28a53dafd063a src/cache/model/entry.rs
|
||||||
@@ -348,80 +349,80 @@ bd831807ca4720b3a41a6ea1d9a6c0ed2d935225e2dacbd9313be064f2e4a20e src/cache/look
|
|||||||
d890524999dc50aeb1dbda90264b46a1d53f08ac923d831b89ba82e4a564d923 src/cache/model/maintenance.rs
|
d890524999dc50aeb1dbda90264b46a1d53f08ac923d831b89ba82e4a564d923 src/cache/model/maintenance.rs
|
||||||
5441fa3a384add28b6fdd15300cf2648f8237dbfc211cad9117754203be76911 src/cache/model/settings.rs
|
5441fa3a384add28b6fdd15300cf2648f8237dbfc211cad9117754203be76911 src/cache/model/settings.rs
|
||||||
55dcc0ad84d6b73689ba43e759d5685c406419c7733e23e78d5b072891ab17d7 src/cache/model/views.rs
|
55dcc0ad84d6b73689ba43e759d5685c406419c7733e23e78d5b072891ab17d7 src/cache/model/views.rs
|
||||||
e26dce02df9c043329ca164fed215d271781bce8fb03240f528331bf3df6b9d7 src/cache/policy.rs
|
0c8b0d550e94d4474dcdf991aa0340228dc5f2f904f39350e6e666a16f16fe87 src/cache/model.rs
|
||||||
989df11e246123f760ef31689370f3500e0913fcc6b70d7ac0c2c95e2f412fb0 src/cache/policy/request.rs
|
989df11e246123f760ef31689370f3500e0913fcc6b70d7ac0c2c95e2f412fb0 src/cache/policy/request.rs
|
||||||
d6051d55168fe1db97980a54c22c708f4f325ba72bfc36f35a1851eb5dcc051d src/cache/policy/response.rs
|
d6051d55168fe1db97980a54c22c708f4f325ba72bfc36f35a1851eb5dcc051d src/cache/policy/response.rs
|
||||||
|
e26dce02df9c043329ca164fed215d271781bce8fb03240f528331bf3df6b9d7 src/cache/policy.rs
|
||||||
7e2bcfbb2b57732cdc704d9df7a9298fb80e735e37984431bc936630e41e7f8a src/cache/range.rs
|
7e2bcfbb2b57732cdc704d9df7a9298fb80e735e37984431bc936630e41e7f8a src/cache/range.rs
|
||||||
7ad96b3baae36ec49c90d03b380e749944fb3d54abb045c90db3a35f6b89b1c1 src/cache/tests.rs
|
|
||||||
9183fa8e6086e92fb148fc278fd866d44e3dd988c848a071e32066e44a1cbf0a src/cache/tests/cold_tier_tests.rs
|
9183fa8e6086e92fb148fc278fd866d44e3dd988c848a071e32066e44a1cbf0a src/cache/tests/cold_tier_tests.rs
|
||||||
3842cdcf7c3414b9c30f5fbed927b93e835eec3ef96d4c6ee44250038b834276 src/cache/tests/dashboard_tests.rs
|
3842cdcf7c3414b9c30f5fbed927b93e835eec3ef96d4c6ee44250038b834276 src/cache/tests/dashboard_tests.rs
|
||||||
d7a02eb7bad37e6a5524600aabb5e60ccf50e26c7a487e2806891c9d8acd48f3 src/cache/tests/http_invalidation_tests.rs
|
d7a02eb7bad37e6a5524600aabb5e60ccf50e26c7a487e2806891c9d8acd48f3 src/cache/tests/http_invalidation_tests.rs
|
||||||
1659ffd8d227d2ec8b98e6a5e06b6143e6ac4ac06ab423c184980abcb47085da src/cache/tests/scope_tests.rs
|
1659ffd8d227d2ec8b98e6a5e06b6143e6ac4ac06ab423c184980abcb47085da src/cache/tests/scope_tests.rs
|
||||||
d4429cf4f35fd8d0082108fb62602fde72c9c2fc6edfadfe3268c6a8214a8f89 src/cache/tests/tests.rs
|
d4429cf4f35fd8d0082108fb62602fde72c9c2fc6edfadfe3268c6a8214a8f89 src/cache/tests/tests.rs
|
||||||
af28534625859ff66011e10c54cff8f82c2cfa1c173c4d99b89c27c1437f0659 src/cache/tests/v022_cache_tests.rs
|
af28534625859ff66011e10c54cff8f82c2cfa1c173c4d99b89c27c1437f0659 src/cache/tests/v022_cache_tests.rs
|
||||||
|
7ad96b3baae36ec49c90d03b380e749944fb3d54abb045c90db3a35f6b89b1c1 src/cache/tests.rs
|
||||||
22f8f16cf7383c579b19810819030072fc827681478e17068dddc85da8dc53ad src/cache/tickets.rs
|
22f8f16cf7383c579b19810819030072fc827681478e17068dddc85da8dc53ad src/cache/tickets.rs
|
||||||
e0146bf5d2e2e33aedcccd9205e5bd457559c9d77dc7ce266f8c165d1b867f0f src/compression.rs
|
|
||||||
4bdbde197d135fee8be20e93427eba8ca7b60b801717ed7ca734319bedb6ef05 src/compression/tests.rs
|
4bdbde197d135fee8be20e93427eba8ca7b60b801717ed7ca734319bedb6ef05 src/compression/tests.rs
|
||||||
7bc8285cb2012506fd1a38a71dffa561f885f4ab65a9b2a7c8344319e3cd1cf6 src/config.rs
|
e0146bf5d2e2e33aedcccd9205e5bd457559c9d77dc7ce266f8c165d1b867f0f src/compression.rs
|
||||||
dbd57ef3307b937614cdfdb6c1df82acb80cbbef39f09d19fe2edfc24334aa58 src/config/backend.rs
|
56b3d37e7447995bec2fdda1c17dcc74b60958a63ca88b88ff57e56347d8b0b9 src/config/backend.rs
|
||||||
beb831a208c4e5f7ebe8327686b1e0edc66608c7032f895cb4fc3366b189aae0 src/config/compile.rs
|
beb831a208c4e5f7ebe8327686b1e0edc66608c7032f895cb4fc3366b189aae0 src/config/compile.rs
|
||||||
dfa89a9e214d0b33b4efce8fa678f1fec17d17656e203acf84dfd09ce33868e0 src/config/internal_routing.rs
|
dfa89a9e214d0b33b4efce8fa678f1fec17d17656e203acf84dfd09ce33868e0 src/config/internal_routing.rs
|
||||||
70741af46ad6f712b0c0e029c066d04c14a689eae0c831af264b09f6e5c41bae src/config/model.rs
|
40e09627e655d9319b576592f8d635e8c2da12905e5cee5952f7b6596010eb8c src/config/model.rs
|
||||||
fc993c356386a9ff17379d48a70ef388df5b2b10ca9ee04f06342f68f9dbbaae src/config/routing.rs
|
fc993c356386a9ff17379d48a70ef388df5b2b10ca9ee04f06342f68f9dbbaae src/config/routing.rs
|
||||||
a7ccffdeeb258adae41c616022ed0181cf590d708d305d48c63317e4a3f68699 src/config/snapshot.rs
|
a7ccffdeeb258adae41c616022ed0181cf590d708d305d48c63317e4a3f68699 src/config/snapshot.rs
|
||||||
41a4fa4f9a919a8c848ee01d01423d82a136790c9d74f27319c1e5a6d9f18097 src/config/tests.rs
|
41a4fa4f9a919a8c848ee01d01423d82a136790c9d74f27319c1e5a6d9f18097 src/config/tests.rs
|
||||||
23541660151d9005555a07db6d491455d61b185f0cc70c3ec3a0bee2aef08dc3 src/db.rs
|
7bc8285cb2012506fd1a38a71dffa561f885f4ab65a9b2a7c8344319e3cd1cf6 src/config.rs
|
||||||
30f0b7269224a64e3f1ec9e6fbe9e27ddb1d308dc84cc9882e50545cf612695d src/db/certificate_api.rs
|
30f0b7269224a64e3f1ec9e6fbe9e27ddb1d308dc84cc9882e50545cf612695d src/db/certificate_api.rs
|
||||||
20ba52d3755c359d670968efa53b0604ff7cbed63a416f9f765b50a1f45074ac src/db/dashboard_presets.rs
|
20ba52d3755c359d670968efa53b0604ff7cbed63a416f9f765b50a1f45074ac src/db/dashboard_presets.rs
|
||||||
2ff744223934685439374572b83fd639bb3eabdbac168bea4a6501a6e9ce0ee0 src/db/history.rs
|
2ff744223934685439374572b83fd639bb3eabdbac168bea4a6501a6e9ce0ee0 src/db/history.rs
|
||||||
c05a02618d476e4670b4f9930555f199cac776cdf09edb8fcc1a675695b8f99f src/db/tests.rs
|
c05a02618d476e4670b4f9930555f199cac776cdf09edb8fcc1a675695b8f99f src/db/tests.rs
|
||||||
|
23541660151d9005555a07db6d491455d61b185f0cc70c3ec3a0bee2aef08dc3 src/db.rs
|
||||||
19ab6c3ae37009c544291cb0b65c1bb9c721e168f95c1ed3fa88155aca7463ad src/demo.rs
|
19ab6c3ae37009c544291cb0b65c1bb9c721e168f95c1ed3fa88155aca7463ad src/demo.rs
|
||||||
e69031875ffec32c9f548c43bed5f1a5c4c626e9568c9173e3b093f9a8b73036 src/diagnostics.rs
|
e69031875ffec32c9f548c43bed5f1a5c4c626e9568c9173e3b093f9a8b73036 src/diagnostics.rs
|
||||||
b45d6040810c93ae2acb04ef6b0a59c189751edf9008cd81a4521c9e04e7f07d src/docker.rs
|
|
||||||
93a8a3f6ba12761ddcbd19f22f32fb2c0e6948b660fb774ddd7ebdba9b6562a5 src/docker/client.rs
|
93a8a3f6ba12761ddcbd19f22f32fb2c0e6948b660fb774ddd7ebdba9b6562a5 src/docker/client.rs
|
||||||
4c2c988191a97f81568a8df64af772463d010844f1abf327871901cdb32d4336 src/docker/model.rs
|
4c2c988191a97f81568a8df64af772463d010844f1abf327871901cdb32d4336 src/docker/model.rs
|
||||||
5f4610c59b2d4ff6a205a2d9ae11bc84be689b2a68302459f546b3f43e53593c src/docker/reconcile.rs
|
5f4610c59b2d4ff6a205a2d9ae11bc84be689b2a68302459f546b3f43e53593c src/docker/reconcile.rs
|
||||||
a12c47df4b90b6fc36c978a42477e6ddffbbbf69aed7252101c2fd829709bd6e src/docker/tests.rs
|
a12c47df4b90b6fc36c978a42477e6ddffbbbf69aed7252101c2fd829709bd6e src/docker/tests.rs
|
||||||
2a02ea2e010cde1b1fe99b2e6baa80ea344ea6b332dbb3c4be795b71541f64a7 src/forwarding.rs
|
b45d6040810c93ae2acb04ef6b0a59c189751edf9008cd81a4521c9e04e7f07d src/docker.rs
|
||||||
057e652f216a1478638cbb53b1c64ac88c7f413a65825caacbf893c5af004a63 src/forwarding/tests.rs
|
057e652f216a1478638cbb53b1c64ac88c7f413a65825caacbf893c5af004a63 src/forwarding/tests.rs
|
||||||
af7a4e91c32ffbe4701c8c06e48ba3f8bbbe55e8b9e877aecb30ccdf858e9e8f src/geoip.rs
|
2a02ea2e010cde1b1fe99b2e6baa80ea344ea6b332dbb3c4be795b71541f64a7 src/forwarding.rs
|
||||||
80850f7acd1ed4c0048b065e9e81740869a8efbb0d9b5d2e83d8ec7fbc494703 src/geoip/mmdb.rs
|
80850f7acd1ed4c0048b065e9e81740869a8efbb0d9b5d2e83d8ec7fbc494703 src/geoip/mmdb.rs
|
||||||
06aa056d789742cc11c8826c338d985e6a6fb22da6c3530937eec38e35478034 src/geoip/mmdb_tests.rs
|
06aa056d789742cc11c8826c338d985e6a6fb22da6c3530937eec38e35478034 src/geoip/mmdb_tests.rs
|
||||||
d3dc58628683472ef4d205fa5c42f0b7ef83cf90846146d96941cd3b36a40766 src/geoip/tests.rs
|
d3dc58628683472ef4d205fa5c42f0b7ef83cf90846146d96941cd3b36a40766 src/geoip/tests.rs
|
||||||
70091bdf6f38f03b6df8c8c4407c300677e57f293130122503f936500963d37c src/geoip/update.rs
|
70091bdf6f38f03b6df8c8c4407c300677e57f293130122503f936500963d37c src/geoip/update.rs
|
||||||
c1b49bef28d87712e4c46138e70b52c4bcfb1a00196579031fac043d0b4aaa7b src/geoip/update_http.rs
|
c1b49bef28d87712e4c46138e70b52c4bcfb1a00196579031fac043d0b4aaa7b src/geoip/update_http.rs
|
||||||
9a912dad0b8d1e10410fd95d0da3684656092ef85cf8b23eda4ffe7fb92921d8 src/geoip/update_tests.rs
|
9a912dad0b8d1e10410fd95d0da3684656092ef85cf8b23eda4ffe7fb92921d8 src/geoip/update_tests.rs
|
||||||
f6ebafafa82391f8cb3b5a09331f3762b6ca5a9fb64bafb5772cde3ab814dfcf src/headers.rs
|
af7a4e91c32ffbe4701c8c06e48ba3f8bbbe55e8b9e877aecb30ccdf858e9e8f src/geoip.rs
|
||||||
e4f07bfb7eb75b6897ef812870caff158679a3046d64582428abe8c6df490dbe src/headers/tests.rs
|
e4f07bfb7eb75b6897ef812870caff158679a3046d64582428abe8c6df490dbe src/headers/tests.rs
|
||||||
9e21edc67a14ef8a2ce3dda0ed18784d0fd0be305973e5d216058b7ac802c6cb src/http3.rs
|
f6ebafafa82391f8cb3b5a09331f3762b6ca5a9fb64bafb5772cde3ab814dfcf src/headers.rs
|
||||||
eb57117938a447d9a6c2ec1806ebd9fecc640a68c88950a8b35fa9bad14d0dc6 src/http3/body.rs
|
eb57117938a447d9a6c2ec1806ebd9fecc640a68c88950a8b35fa9bad14d0dc6 src/http3/body.rs
|
||||||
ed25da264a2d25b40c4fcddc97c626a3a43d4f3a9be6c6d31af58b9e4925c198 src/http3/diagnostics.rs
|
ed25da264a2d25b40c4fcddc97c626a3a43d4f3a9be6c6d31af58b9e4925c198 src/http3/diagnostics.rs
|
||||||
37f54961d8f52b79a75fb2be31e81f4fdb1e66b06350345c4483d6197b8a0bbc src/http3/identity.rs
|
37f54961d8f52b79a75fb2be31e81f4fdb1e66b06350345c4483d6197b8a0bbc src/http3/identity.rs
|
||||||
f2a8c2a98f4ccfb708f9d75a48ec7b351232be9b8a4364b7e63ba14d28eead7c src/http3/settings.rs
|
f2a8c2a98f4ccfb708f9d75a48ec7b351232be9b8a4364b7e63ba14d28eead7c src/http3/settings.rs
|
||||||
a31db7eac12b578b1eb5a74fae98bbe36312da95b7d7173135dbc41fc454da21 src/http3/tests.rs
|
a31db7eac12b578b1eb5a74fae98bbe36312da95b7d7173135dbc41fc454da21 src/http3/tests.rs
|
||||||
|
9e21edc67a14ef8a2ce3dda0ed18784d0fd0be305973e5d216058b7ac802c6cb src/http3.rs
|
||||||
68fb5ab6a889995a66ad12cb6acf88c5d04f0aca572e2ae15f1a9cd171a5f24b src/lib.rs
|
68fb5ab6a889995a66ad12cb6acf88c5d04f0aca572e2ae15f1a9cd171a5f24b src/lib.rs
|
||||||
2551189a3e5701371026c9abd2c5d44d37495f28fb67e220180421bfd315e3dd src/logging.rs
|
|
||||||
18c8d74c21a47f234be93551d7264b1f8f8c00d1bbfbe555d91618c58cea0740 src/logging/error_runtime.rs
|
18c8d74c21a47f234be93551d7264b1f8f8c00d1bbfbe555d91618c58cea0740 src/logging/error_runtime.rs
|
||||||
33b4b7f69560c2acc0de0eac62604161d38dbd7044c5789a1352f0cd3882ea70 src/logging/format.rs
|
bc3873c6f22d1ee7fa76ae586547c9867e6eeaec8266e3ed1f529c87108df2b6 src/logging/format.rs
|
||||||
f5815d778cc1785723faed4abb15f9880f22b6524b5289fe1e7158905aac0986 src/logging/model.rs
|
f5815d778cc1785723faed4abb15f9880f22b6524b5289fe1e7158905aac0986 src/logging/model.rs
|
||||||
42fef80af50735cd566c6801dad86ba81be98cf4a8ec7d45c2ea26f53f556a22 src/logging/runtime.rs
|
42fef80af50735cd566c6801dad86ba81be98cf4a8ec7d45c2ea26f53f556a22 src/logging/runtime.rs
|
||||||
584782215ea78a88526cdb5515031d8d5b87910875e26c0024b93a06680f6791 src/logging/tests.rs
|
7ee1eb1d3b52b4c14303f8ca14a1924d4d6bbe75b2e43ce3ca47d7958f792c7d src/logging/tests.rs
|
||||||
3836ed14b6710e183f048ee4d7807a35366c27a27338057fe4a2811129b63302 src/main.rs
|
2551189a3e5701371026c9abd2c5d44d37495f28fb67e220180421bfd315e3dd src/logging.rs
|
||||||
fc8e99eac83c083d65101f6402aacbcc8392d66508c31566a50de3ebcb12e7da src/main/admin_runtime.rs
|
fc8e99eac83c083d65101f6402aacbcc8392d66508c31566a50de3ebcb12e7da src/main/admin_runtime.rs
|
||||||
42a9197475823f67c1ca762951ede5d7a2f10124bd6ed4d1a3365f4297be894c src/main/bootstrap.rs
|
42a9197475823f67c1ca762951ede5d7a2f10124bd6ed4d1a3365f4297be894c src/main/bootstrap.rs
|
||||||
5a98d0e249338e73aa57ae2e352dc16db2f79c2d042c1544ce1c2022da76a31c src/main/proxy_runtime.rs
|
5a98d0e249338e73aa57ae2e352dc16db2f79c2d042c1544ce1c2022da76a31c src/main/proxy_runtime.rs
|
||||||
4dd7c1084a6214c0f2513ebf86fe8ef144470695557772bfe25979edd64491ab src/main/shutdown.rs
|
|
||||||
0a6578a0f4023b9f8d73043bf942dc5e096ef9afb8c0d2f131c14f65d08ac01d src/main/shutdown/tests.rs
|
0a6578a0f4023b9f8d73043bf942dc5e096ef9afb8c0d2f131c14f65d08ac01d src/main/shutdown/tests.rs
|
||||||
|
4dd7c1084a6214c0f2513ebf86fe8ef144470695557772bfe25979edd64491ab src/main/shutdown.rs
|
||||||
e5c2e9189777725f4afa1c3c052e4f75047ec3f2f486630d990f5d3c194bcc96 src/main/tasks.rs
|
e5c2e9189777725f4afa1c3c052e4f75047ec3f2f486630d990f5d3c194bcc96 src/main/tasks.rs
|
||||||
49d7e104585c8791ac9a203dddd95802784b68c0ba65d6f90f3d57154b4c7871 src/metrics.rs
|
3836ed14b6710e183f048ee4d7807a35366c27a27338057fe4a2811129b63302 src/main.rs
|
||||||
201ab702722d6d21585fe8bb49939150d61bfac7ed8dc198b98c2cc6098ffb5f src/metrics/global.rs
|
201ab702722d6d21585fe8bb49939150d61bfac7ed8dc198b98c2cc6098ffb5f src/metrics/global.rs
|
||||||
49b11df65b4fb0b5b727f9f867436584680b45e3f4fbd53f74bc0cab8b9a88ec src/metrics/vhost.rs
|
|
||||||
a54b5b34ea65f29723b89b81bf7968a238e8247b9c9760f3430d3504cb1017c9 src/metrics/vhost/tests.rs
|
a54b5b34ea65f29723b89b81bf7968a238e8247b9c9760f3430d3504cb1017c9 src/metrics/vhost/tests.rs
|
||||||
a4702c95c7e5077c2ccff86e2e3216e1da6ff9ee4383ae199a0aff2f78db325f src/not_found.rs
|
49b11df65b4fb0b5b727f9f867436584680b45e3f4fbd53f74bc0cab8b9a88ec src/metrics/vhost.rs
|
||||||
|
49d7e104585c8791ac9a203dddd95802784b68c0ba65d6f90f3d57154b4c7871 src/metrics.rs
|
||||||
c915d30bbd7032d867e7916b4cd45f3bb7e7604d3f4558f4383c59394b4300c6 src/not_found/tests.rs
|
c915d30bbd7032d867e7916b4cd45f3bb7e7604d3f4558f4383c59394b4300c6 src/not_found/tests.rs
|
||||||
d66936cc15fd5d56566d40fa8cab93f80d94b05f10ac44478a30f63572a95e32 src/pages.rs
|
a4702c95c7e5077c2ccff86e2e3216e1da6ff9ee4383ae199a0aff2f78db325f src/not_found.rs
|
||||||
da40e8ece87245efc49a0c4e750526b1d19fd97565856bd5caf641fcc1dfe18d src/pages/tests.rs
|
da40e8ece87245efc49a0c4e750526b1d19fd97565856bd5caf641fcc1dfe18d src/pages/tests.rs
|
||||||
0dba7b6a33866cc7bbe05509b01961e545892645d1dad4eb88ac8a4bec65e3bf src/prometheus.rs
|
d66936cc15fd5d56566d40fa8cab93f80d94b05f10ac44478a30f63572a95e32 src/pages.rs
|
||||||
cc6fb14351b009a16d07ed0f412c2bcc68cd7e551421aea03d8d97ceec9bee40 src/prometheus/core.rs
|
cc6fb14351b009a16d07ed0f412c2bcc68cd7e551421aea03d8d97ceec9bee40 src/prometheus/core.rs
|
||||||
c46882ed26742d93806a976257674326e105b8ca1fc23f5ca81e317b268057aa src/prometheus/docker_misc.rs
|
c46882ed26742d93806a976257674326e105b8ca1fc23f5ca81e317b268057aa src/prometheus/docker_misc.rs
|
||||||
d3c6b08088df0003144544936a55e2a3661aac85292821b594f00adfd19a2951 src/prometheus/model.rs
|
d3c6b08088df0003144544936a55e2a3661aac85292821b594f00adfd19a2951 src/prometheus/model.rs
|
||||||
@@ -429,139 +430,140 @@ d3c6b08088df0003144544936a55e2a3661aac85292821b594f00adfd19a2951 src/prometheus
|
|||||||
028e1dd9f2ec2afaf699a6b21c2d4b0d96e76f11f5e4ed009c233dadf0f3be51 src/prometheus/traffic.rs
|
028e1dd9f2ec2afaf699a6b21c2d4b0d96e76f11f5e4ed009c233dadf0f3be51 src/prometheus/traffic.rs
|
||||||
e03f0d6b3f35dae6b98c394837aa0d17e4d73a8306767b4c607868bc00c30286 src/prometheus/vhosts_backends.rs
|
e03f0d6b3f35dae6b98c394837aa0d17e4d73a8306767b4c607868bc00c30286 src/prometheus/vhosts_backends.rs
|
||||||
fb2d8d45cd2e947f783eb981b37fa418c39fcb327a3af17a648fadea7f37f888 src/prometheus/web_php.rs
|
fb2d8d45cd2e947f783eb981b37fa418c39fcb327a3af17a648fadea7f37f888 src/prometheus/web_php.rs
|
||||||
4c7199c04e6d314e89825f80feaab35a2efb3b893511f70da0cda46ab1d0bc9e src/proxy/body.rs
|
0dba7b6a33866cc7bbe05509b01961e545892645d1dad4eb88ac8a4bec65e3bf src/prometheus.rs
|
||||||
f0f3e21350e4fb15fa2ae282da6b290857dcd6716e62b183e9ecb728b7c24c63 src/proxy/body/tests.rs
|
f0f3e21350e4fb15fa2ae282da6b290857dcd6716e62b183e9ecb728b7c24c63 src/proxy/body/tests.rs
|
||||||
|
ea38488f8507609dbf6e5ae6e9c10f4045bc424a42e8eb11b608538a2d55d6ee src/proxy/body.rs
|
||||||
b88d1d7a6837a2a470e5863f1f3247878daee62791fc3d8e72baeb66469bdfbf src/proxy/cache_helpers.rs
|
b88d1d7a6837a2a470e5863f1f3247878daee62791fc3d8e72baeb66469bdfbf src/proxy/cache_helpers.rs
|
||||||
aa49c9928bb91e3d5bae0d340d88396a0417b9edec6192d41e1403533319a897 src/proxy/cache_http_invalidation.rs
|
aa49c9928bb91e3d5bae0d340d88396a0417b9edec6192d41e1403533319a897 src/proxy/cache_http_invalidation.rs
|
||||||
676c1b325fd8e55bcdd86451c7d1d8b8d347ca00e8da6b3e5b148a58c376a9b4 src/proxy/cache_plan.rs
|
|
||||||
3404b03096862de1050088f62cdd811ea1ab61d191f902501173107f81f23b9b src/proxy/cache_plan/tests.rs
|
3404b03096862de1050088f62cdd811ea1ab61d191f902501173107f81f23b9b src/proxy/cache_plan/tests.rs
|
||||||
|
676c1b325fd8e55bcdd86451c7d1d8b8d347ca00e8da6b3e5b148a58c376a9b4 src/proxy/cache_plan.rs
|
||||||
a8848cbdf85368548b003af2b43823c453866c472af4c7d2ff0ec7da14c44c8d src/proxy/error_fallback.rs
|
a8848cbdf85368548b003af2b43823c453866c472af4c7d2ff0ec7da14c44c8d src/proxy/error_fallback.rs
|
||||||
bf2e6bbd64fb45fceed54af0bff1c1e00da22b79c64dd8f5c23d2af0dbab0b7d src/proxy/forward/cache_lookup.rs
|
bf2e6bbd64fb45fceed54af0bff1c1e00da22b79c64dd8f5c23d2af0dbab0b7d src/proxy/forward/cache_lookup.rs
|
||||||
cfa941b60b5d167ec9d8e2566ea3342b588d1a9078a6ca711ad6062ddf00fec9 src/proxy/forward/response.rs
|
cfa941b60b5d167ec9d8e2566ea3342b588d1a9078a6ca711ad6062ddf00fec9 src/proxy/forward/response.rs
|
||||||
8168a42c3992d002e87fdd5d52a37f53dcdf69cbc859221350d888e94c305ab8 src/proxy/forward/route_cache.rs
|
7a5f43fe65e5a746eb84881da0bf784215081ead66d18faa7780533ad5df9c8c src/proxy/forward/route_cache.rs
|
||||||
96c97928986ca89c2d6d415d5b107b9cc7228410bae93a2c08c24974324f4d8d src/proxy/forward/success_finish.rs
|
96c97928986ca89c2d6d415d5b107b9cc7228410bae93a2c08c24974324f4d8d src/proxy/forward/success_finish.rs
|
||||||
0a921474ef2b93eabdaf3888651cf29130eace5ccb1e0f5d6bc25e6aa69280be src/proxy/forward/success_prepare.rs
|
0a921474ef2b93eabdaf3888651cf29130eace5ccb1e0f5d6bc25e6aa69280be src/proxy/forward/success_prepare.rs
|
||||||
bb24da9c9ab986a9c4d4144d4d1be0f661561d4afc755f298b58bc679b182850 src/proxy/forward/upstream.rs
|
bb24da9c9ab986a9c4d4144d4d1be0f661561d4afc755f298b58bc679b182850 src/proxy/forward/upstream.rs
|
||||||
11dccc239ac8a8e9ea06e884c2f2658f86b7807d14a59b8e052bc7dd75e86d63 src/proxy/forward/web_source.rs
|
11dccc239ac8a8e9ea06e884c2f2658f86b7807d14a59b8e052bc7dd75e86d63 src/proxy/forward/web_source.rs
|
||||||
facde401ba5bcbafdcea5524f236cfae37eec11144ceeea879e83314c84bc97e src/proxy/forward_entry.rs
|
facde401ba5bcbafdcea5524f236cfae37eec11144ceeea879e83314c84bc97e src/proxy/forward_entry.rs
|
||||||
9b25f5e3ea4443a63ee6f45d12e1957dd316fe8e85325fc00ea416faaab1025a src/proxy/h2_graceful.rs
|
9b25f5e3ea4443a63ee6f45d12e1957dd316fe8e85325fc00ea416faaab1025a src/proxy/h2_graceful.rs
|
||||||
c438066616527a3108f2ad53e3698ae9b2a80961714394cdd0a450c92f99d992 src/proxy/headers.rs
|
|
||||||
5cb7522ceb9a9f083a15596ac4898559295e38d1138c80099577211de8a868ec src/proxy/headers/tests.rs
|
5cb7522ceb9a9f083a15596ac4898559295e38d1138c80099577211de8a868ec src/proxy/headers/tests.rs
|
||||||
|
c438066616527a3108f2ad53e3698ae9b2a80961714394cdd0a450c92f99d992 src/proxy/headers.rs
|
||||||
3f25429418941eb72c3847125340db74684ad316eb278ecf658953026fd41f4f src/proxy/mod.rs
|
3f25429418941eb72c3847125340db74684ad316eb278ecf658953026fd41f4f src/proxy/mod.rs
|
||||||
55133ceace2e5262d9c54fa41bea099a27b817d1e09c1cd0e2493fd9cee4da38 src/proxy/redirect_helpers.rs
|
55133ceace2e5262d9c54fa41bea099a27b817d1e09c1cd0e2493fd9cee4da38 src/proxy/redirect_helpers.rs
|
||||||
c61738672f210e97333c8c89f9b35f8db454cbc1c36955288dfa4cfff2bbbc04 src/proxy/request_id.rs
|
d2df55b6ccfc7ceb8a3d2c49f664acd183448e3d932d5399d6692e87f79a094b src/proxy/request_id/tests.rs
|
||||||
6ff45990f6beb914e89924bec2c41022f3240a14357cf66ec4f8ada414a49767 src/proxy/request_id/tests.rs
|
96da894a86c05f8f467bf83cc23e56627ed3f9f490ffc936872d70126c8ecb41 src/proxy/request_id.rs
|
||||||
8ad3619359f3befa14ea71ba43c638fea8f4d8a859cd07e4ed505731b8e32e72 src/proxy/tests/authority_tests.rs
|
e56c65c85e42ee4fe6adf3655f3b2d176798e37c648db6bfb8e1602300b723eb src/proxy/tests/authority_tests.rs
|
||||||
1aa9bbbfb2659facdaeaf185e11221b1c8cd5fe6e23c7c1dacd3aa55e3db4fcb src/proxy/tests/cache_fast_path_tests.rs
|
1aa9bbbfb2659facdaeaf185e11221b1c8cd5fe6e23c7c1dacd3aa55e3db4fcb src/proxy/tests/cache_fast_path_tests.rs
|
||||||
0f2eacadf1447db8aa1c1a78005aa262e0f747096bfe7e0a0e41a2cd31a0d17f src/proxy/tests/h3_navigation_tests.rs
|
0f2eacadf1447db8aa1c1a78005aa262e0f747096bfe7e0a0e41a2cd31a0d17f src/proxy/tests/h3_navigation_tests.rs
|
||||||
d134b0eb617f82f9971b3f3461379ea37c57bd0079bf54748d0c434b2ef1b475 src/proxy/tests/http_invalidation_tests.rs
|
d134b0eb617f82f9971b3f3461379ea37c57bd0079bf54748d0c434b2ef1b475 src/proxy/tests/http_invalidation_tests.rs
|
||||||
d5717fac0e7d2cb2939626eb95f4520241b677fe1f3e045df12c100315302a5a src/proxy/types.rs
|
7789a80202d606dcea3776345464a5487bf6124e4878bf8c94db91b67f0d4eb8 src/proxy/types.rs
|
||||||
8d7848645c25932589d0dfc54149bb71a51edd7188aed60dc4d6ca8179b361ab src/proxy/upstream_helpers.rs
|
1cbca5fbe91f40447e9eadc349e2d56f220119d14504f07ce90ed70f945a767e src/proxy/upstream_helpers.rs
|
||||||
2d9142e3ae95895b5271b4009ab48236a3a2074ce51179c021193b35777560e4 src/proxy/web_cache_revalidation.rs
|
|
||||||
d7b4b809b12ee89293df45e9a64b1c9981fb3f89deaab3762f4a3ad3992dd7b1 src/proxy/web_cache_revalidation/tests.rs
|
d7b4b809b12ee89293df45e9a64b1c9981fb3f89deaab3762f4a3ad3992dd7b1 src/proxy/web_cache_revalidation/tests.rs
|
||||||
69f775f6746b4c6d729dc10961dbef54168846f4ce9cf7fe453ab5a2b879c9b8 src/proxy/websocket.rs
|
2d9142e3ae95895b5271b4009ab48236a3a2074ce51179c021193b35777560e4 src/proxy/web_cache_revalidation.rs
|
||||||
d866e7e72dee6ff54c2418c34e9899cbcd7e4e027d9cbe2b625044dc9062e4ee src/proxy/websocket/handshake.rs
|
d866e7e72dee6ff54c2418c34e9899cbcd7e4e027d9cbe2b625044dc9062e4ee src/proxy/websocket/handshake.rs
|
||||||
7e9c4d4c207badabf90630223964bb2ad641f06d4149843cab751f192b8b4adf src/proxy/websocket/tests.rs
|
7e9c4d4c207badabf90630223964bb2ad641f06d4149843cab751f192b8b4adf src/proxy/websocket/tests.rs
|
||||||
a44421714aab37f7ceda19e3ec2512c645d2a3ce5dcb3da5bc7a0d87a442d6a8 src/proxy/websocket/tunnel.rs
|
a44421714aab37f7ceda19e3ec2512c645d2a3ce5dcb3da5bc7a0d87a442d6a8 src/proxy/websocket/tunnel.rs
|
||||||
15fabd38576b61f650c039acdbf7ac5a5bd24330062475b94315285b2dc258b6 src/proxy/websocket/validation.rs
|
15fabd38576b61f650c039acdbf7ac5a5bd24330062475b94315285b2dc258b6 src/proxy/websocket/validation.rs
|
||||||
545247eb00b0116efbd4cc913cc251195a55feded1530e0d8d8945abbae78039 src/rate_limit.rs
|
69f775f6746b4c6d729dc10961dbef54168846f4ce9cf7fe453ab5a2b879c9b8 src/proxy/websocket.rs
|
||||||
e7e3a898e2c769b1ef11e58a13c1053104ada93dd694f8a03ea4b647c44c7d69 src/rate_limit/tests.rs
|
e7e3a898e2c769b1ef11e58a13c1053104ada93dd694f8a03ea4b647c44c7d69 src/rate_limit/tests.rs
|
||||||
d40ad63939097d2b91339127d5835a74b618d83b7ba31db0c512f05a82107d6e src/redirect.rs
|
545247eb00b0116efbd4cc913cc251195a55feded1530e0d8d8945abbae78039 src/rate_limit.rs
|
||||||
811c83ae9fd0f5a13d35b5443cd37843f82b9d600bee4bb136ba9b87732a5347 src/redirect/tests.rs
|
811c83ae9fd0f5a13d35b5443cd37843f82b9d600bee4bb136ba9b87732a5347 src/redirect/tests.rs
|
||||||
d0939e1b0829c25356a0b67ecb3a178c74936dd07baa15fee24eb32544db6cad src/runtime.rs
|
d40ad63939097d2b91339127d5835a74b618d83b7ba31db0c512f05a82107d6e src/redirect.rs
|
||||||
8d0d7b01871c8c588c40a54330a1053c85024655fbe38516ca6c94c3c19a8956 src/runtime/certificates.rs
|
8d0d7b01871c8c588c40a54330a1053c85024655fbe38516ca6c94c3c19a8956 src/runtime/certificates.rs
|
||||||
2ccafa8a5a8462417f65d05a0c6c42f294afa4ad1067ea0b93623181546d1f96 src/runtime/constructors.rs
|
2ccafa8a5a8462417f65d05a0c6c42f294afa4ad1067ea0b93623181546d1f96 src/runtime/constructors.rs
|
||||||
92b4b284f1b69dca58e4e3f76199f0aecc397eed26d10123b427af1bb8a4a57e src/runtime/docker.rs
|
92b4b284f1b69dca58e4e3f76199f0aecc397eed26d10123b427af1bb8a4a57e src/runtime/docker.rs
|
||||||
ee2050b9f8efb45a209c91d76043a1ba29c4289978896aaf7e7d344d48fdc369 src/runtime/tests.rs
|
ee2050b9f8efb45a209c91d76043a1ba29c4289978896aaf7e7d344d48fdc369 src/runtime/tests.rs
|
||||||
779137f320133ec96f73c8b3d357ad4f0b825ee2367e9e8300f4f143b38eecb7 src/runtime/types.rs
|
779137f320133ec96f73c8b3d357ad4f0b825ee2367e9e8300f4f143b38eecb7 src/runtime/types.rs
|
||||||
5947afaf7d070ea2047eb7969a8e0d84f981e91ace283f6506cf7685fb8afab9 src/runtime/updates.rs
|
5947afaf7d070ea2047eb7969a8e0d84f981e91ace283f6506cf7685fb8afab9 src/runtime/updates.rs
|
||||||
208a378b14ca80e1412ffa19ef1b140594182971e2e797ee0bb95bcdb8404da7 src/secret_store.rs
|
d0939e1b0829c25356a0b67ecb3a178c74936dd07baa15fee24eb32544db6cad src/runtime.rs
|
||||||
6dca8da072a3bd610704a391bb6e25c9042971f4ebc60edb47665ce1d74cbc58 src/secret_store/tests.rs
|
6dca8da072a3bd610704a391bb6e25c9042971f4ebc60edb47665ce1d74cbc58 src/secret_store/tests.rs
|
||||||
6fa1d8c352bce7a16ff0208bc4cdbe80404715df0aff4ed26910a5df57cbbcd4 src/security.rs
|
208a378b14ca80e1412ffa19ef1b140594182971e2e797ee0bb95bcdb8404da7 src/secret_store.rs
|
||||||
0e5fc2aff856bf6fd959cba12b5ddd1e3b3cbeb0fbaadde906c811cdfafdaae7 src/security/tests.rs
|
0e5fc2aff856bf6fd959cba12b5ddd1e3b3cbeb0fbaadde906c811cdfafdaae7 src/security/tests.rs
|
||||||
98c52aa3b50d2e211ab752ccaf353c9a8c1500a87f9c1684b5dd0ba9d10e4619 src/server.rs
|
6fa1d8c352bce7a16ff0208bc4cdbe80404715df0aff4ed26910a5df57cbbcd4 src/security.rs
|
||||||
f2f6196632b2fdb2444189624f961edaf5bdfff57f700b0207b57e2491c1daa5 src/server/http.rs
|
f2f6196632b2fdb2444189624f961edaf5bdfff57f700b0207b57e2491c1daa5 src/server/http.rs
|
||||||
050c48ea1127aa87dba92c074ab84e8346e65dbe253621ea53f8ca2f68d791ab src/server/http1_connection.rs
|
050c48ea1127aa87dba92c074ab84e8346e65dbe253621ea53f8ca2f68d791ab src/server/http1_connection.rs
|
||||||
8c6ca5eaffb9acab57199d0349722703b903cfff3752baad2cf2596bd51188de src/server/listeners.rs
|
8c6ca5eaffb9acab57199d0349722703b903cfff3752baad2cf2596bd51188de src/server/listeners.rs
|
||||||
4424a99b0b688d1119ee25626778b4804aedfaa0799a4a9bc0ee99bc5c7ba96b src/server/sendfile.rs
|
4424a99b0b688d1119ee25626778b4804aedfaa0799a4a9bc0ee99bc5c7ba96b src/server/sendfile.rs
|
||||||
71899a9b1897fa22ab9e8eb6a670054a6d382bad78714006b9b218d07ba99902 src/server/serve.rs
|
|
||||||
e9e478cf45b88994eaffd115f51764b6b07852ee3c941cafdabb20584d3dabc0 src/server/serve/tests.rs
|
e9e478cf45b88994eaffd115f51764b6b07852ee3c941cafdabb20584d3dabc0 src/server/serve/tests.rs
|
||||||
|
71899a9b1897fa22ab9e8eb6a670054a6d382bad78714006b9b218d07ba99902 src/server/serve.rs
|
||||||
960a82e02f09d75141fe3c1eecca915b66f17fdc8167196cd2fe21d5e6859376 src/server/tls_runtime.rs
|
960a82e02f09d75141fe3c1eecca915b66f17fdc8167196cd2fe21d5e6859376 src/server/tls_runtime.rs
|
||||||
73ec453ac2850f6963f5bc33401cb8c92aa26d5123f15d68e6633860d91f265e src/settings.rs
|
98c52aa3b50d2e211ab752ccaf353c9a8c1500a87f9c1684b5dd0ba9d10e4619 src/server.rs
|
||||||
240ecdd70e8662ff3b84c21830dc0cbbbacadd755d56146e54214bc2887f068c src/settings/public_origin.rs
|
240ecdd70e8662ff3b84c21830dc0cbbbacadd755d56146e54214bc2887f068c src/settings/public_origin.rs
|
||||||
1f1121c3562c8f8f3fdee2113be2afffb8849be2d303e4c4409f87478b6e3307 src/settings/tests.rs
|
1f1121c3562c8f8f3fdee2113be2afffb8849be2d303e4c4409f87478b6e3307 src/settings/tests.rs
|
||||||
9dbf814870b8636770f579c3d36d16f5b6afe8bc66adfad356c26d7ae7dbce45 src/stream.rs
|
73ec453ac2850f6963f5bc33401cb8c92aa26d5123f15d68e6633860d91f265e src/settings.rs
|
||||||
254840126be2310426f6332f5efbe98147d9d8de1999731f40a3d13325c1dc6c src/stream/health.rs
|
254840126be2310426f6332f5efbe98147d9d8de1999731f40a3d13325c1dc6c src/stream/health.rs
|
||||||
bdc56be7dae85a97a4d5b8d46ef31ec4177292b1cadd507fe423b6d4ee1403bd src/stream/model.rs
|
bdc56be7dae85a97a4d5b8d46ef31ec4177292b1cadd507fe423b6d4ee1403bd src/stream/model.rs
|
||||||
de138a4ac68bcddba3a4f17ceba008bab643359d76a68726a755069f19334bed src/stream/pool.rs
|
de138a4ac68bcddba3a4f17ceba008bab643359d76a68726a755069f19334bed src/stream/pool.rs
|
||||||
6ec42b8647c95a0c2025462e0be29c71481ce1c3b1f4d4193926471f1cf06be0 src/stream/runtime.rs
|
6ec42b8647c95a0c2025462e0be29c71481ce1c3b1f4d4193926471f1cf06be0 src/stream/runtime.rs
|
||||||
9346cbd71e006e41a7188f28eb86f9b00bac822e4cb31c76c8d6d2ec5d4c4711 src/stream/tests.rs
|
9346cbd71e006e41a7188f28eb86f9b00bac822e4cb31c76c8d6d2ec5d4c4711 src/stream/tests.rs
|
||||||
3070d78a7b88c2e47ed59960fa35e7d220a4cd7d78e48f6c6d2bcc5ff77f9620 src/system_stats/linux.rs
|
9dbf814870b8636770f579c3d36d16f5b6afe8bc66adfad356c26d7ae7dbce45 src/stream.rs
|
||||||
d9123c623e2a97d09e41edaa29993b4b2c8cba39a3abdf2b48a205aa9a9c2939 src/system_stats/linux/tests.rs
|
d9123c623e2a97d09e41edaa29993b4b2c8cba39a3abdf2b48a205aa9a9c2939 src/system_stats/linux/tests.rs
|
||||||
|
3070d78a7b88c2e47ed59960fa35e7d220a4cd7d78e48f6c6d2bcc5ff77f9620 src/system_stats/linux.rs
|
||||||
751d59582fb92c84e0c0cc7c0855c9d0a545805c9ba3be61826e50fb96c297ed src/system_stats/mod.rs
|
751d59582fb92c84e0c0cc7c0855c9d0a545805c9ba3be61826e50fb96c297ed src/system_stats/mod.rs
|
||||||
050aa831b1012c4aaade63863f433f01bfacf5d3f95787e57975572116a30ab2 src/system_stats/tests.rs
|
050aa831b1012c4aaade63863f433f01bfacf5d3f95787e57975572116a30ab2 src/system_stats/tests.rs
|
||||||
7467d83066bb6986d8c9103597f7a7617ac677579ed46d573c573ff6ca57bbd9 src/tinyauth.rs
|
|
||||||
0e1d87554db55e724f30c41ec4a5c80bdb8fc9c8cba8700ac509864d4abf8871 src/tinyauth/tests.rs
|
0e1d87554db55e724f30c41ec4a5c80bdb8fc9c8cba8700ac509864d4abf8871 src/tinyauth/tests.rs
|
||||||
1084cccd9de28acd6cb0f0813de7c0953910f51726f73f4acdb2e3ada4593976 src/tls.rs
|
7467d83066bb6986d8c9103597f7a7617ac677579ed46d573c573ff6ca57bbd9 src/tinyauth.rs
|
||||||
4972a436f8878dec5f9eb8ff17eb82670b0bfd9e94e821c516575479f5fc1919 src/tls/certificates.rs
|
4972a436f8878dec5f9eb8ff17eb82670b0bfd9e94e821c516575479f5fc1919 src/tls/certificates.rs
|
||||||
436575144aa352498a4696f12c2258bef3a898f3f50e6fbc6d67c3b93afa099f src/tls/external_paths.rs
|
436575144aa352498a4696f12c2258bef3a898f3f50e6fbc6d67c3b93afa099f src/tls/external_paths.rs
|
||||||
3e6947dde167f82a5efc407ccf9bd4c9f5b26cc8633d1418a10284bc1a1503d4 src/tls/server_config.rs
|
3e6947dde167f82a5efc407ccf9bd4c9f5b26cc8633d1418a10284bc1a1503d4 src/tls/server_config.rs
|
||||||
31c0f51a3a0bab433f438c3ba1b1cdaf3c63fae6086e7d99b3464a537f75a5e1 src/tls/tests.rs
|
|
||||||
2af2164ecdf2b7fd9eef7c6e358dec053dfac9aedaa501dbb75df742d18638b2 src/tls/tests/acme.rs
|
2af2164ecdf2b7fd9eef7c6e358dec053dfac9aedaa501dbb75df742d18638b2 src/tls/tests/acme.rs
|
||||||
93b359e9defd62506729bc90e56c96783e2f14dd477dd67f337ca83149da7168 src/tls/tests/external_paths.rs
|
93b359e9defd62506729bc90e56c96783e2f14dd477dd67f337ca83149da7168 src/tls/tests/external_paths.rs
|
||||||
|
31c0f51a3a0bab433f438c3ba1b1cdaf3c63fae6086e7d99b3464a537f75a5e1 src/tls/tests.rs
|
||||||
10c4a187e3aeb0c72a8c8968ea0cc8bfae4e3cb2f3d834ebd3da1056c4171ec5 src/tls/types.rs
|
10c4a187e3aeb0c72a8c8968ea0cc8bfae4e3cb2f3d834ebd3da1056c4171ec5 src/tls/types.rs
|
||||||
c2f802d95da4332fb8480e83f0c7502334457b3408141c1c4516c9ba320a0463 src/traffic.rs
|
1084cccd9de28acd6cb0f0813de7c0953910f51726f73f4acdb2e3ada4593976 src/tls.rs
|
||||||
36301bcbd20b557dd3d58e77a9175f3581947f577c0bb0b972899cec6786b03f src/traffic/tests.rs
|
36301bcbd20b557dd3d58e77a9175f3581947f577c0bb0b972899cec6786b03f src/traffic/tests.rs
|
||||||
|
c2f802d95da4332fb8480e83f0c7502334457b3408141c1c4516c9ba320a0463 src/traffic.rs
|
||||||
d88c92f5a2a7773bc3e715d24039db35da4df53881f1a0859eec819b96f06d3b src/transform/apply.rs
|
d88c92f5a2a7773bc3e715d24039db35da4df53881f1a0859eec819b96f06d3b src/transform/apply.rs
|
||||||
87f8af5261d79072f8215f1fb8a90715a58e7626544fd8176ce840e3111bdb92 src/transform/compile.rs
|
87f8af5261d79072f8215f1fb8a90715a58e7626544fd8176ce840e3111bdb92 src/transform/compile.rs
|
||||||
b2c5236589093454ec60984b785ad6a4af6149d47f6db37d8e08c17fec7a2c1b src/transform/css.rs
|
b2c5236589093454ec60984b785ad6a4af6149d47f6db37d8e08c17fec7a2c1b src/transform/css.rs
|
||||||
5478670cef87777b14a2dab308f5a9182df56d7ea2f5625bdc94aa7e3d661503 src/transform/html.rs
|
|
||||||
aa99b0d3029ef92c78371cb90e11f2026cce890d1be8e10ebd7fa9bc5cb13287 src/transform/html/tests.rs
|
aa99b0d3029ef92c78371cb90e11f2026cce890d1be8e10ebd7fa9bc5cb13287 src/transform/html/tests.rs
|
||||||
a1d2fec07617c8a8dc425bfaeaf77c844152a0a174568a88a5baf4c317cc6c5c src/transform/js.rs
|
5478670cef87777b14a2dab308f5a9182df56d7ea2f5625bdc94aa7e3d661503 src/transform/html.rs
|
||||||
cf5195ab6bacccae0082da7b3f1bd0382b73fdeb3607f4ae569ca6daab9d10d0 src/transform/js/tests.rs
|
cf5195ab6bacccae0082da7b3f1bd0382b73fdeb3607f4ae569ca6daab9d10d0 src/transform/js/tests.rs
|
||||||
226ae561dc7b0243c04e55e28cdfd2b76acd48cf614d1919b81c196660b03cfb src/transform/json.rs
|
a1d2fec07617c8a8dc425bfaeaf77c844152a0a174568a88a5baf4c317cc6c5c src/transform/js.rs
|
||||||
216e24e29ea87be4a124f95f898e155f127fd959d7d5d9b30f8cd0b2b5018f30 src/transform/json/tests.rs
|
216e24e29ea87be4a124f95f898e155f127fd959d7d5d9b30f8cd0b2b5018f30 src/transform/json/tests.rs
|
||||||
|
226ae561dc7b0243c04e55e28cdfd2b76acd48cf614d1919b81c196660b03cfb src/transform/json.rs
|
||||||
6a8c28be93fb590942493c075b29ace1527981542bd183f232aa82b62e951eca src/transform/mod.rs
|
6a8c28be93fb590942493c075b29ace1527981542bd183f232aa82b62e951eca src/transform/mod.rs
|
||||||
fde2fa3aa94b30d8536afec1c11348cfbd922d0b5ff89e91d34266e8e3863e26 src/transform/model.rs
|
fde2fa3aa94b30d8536afec1c11348cfbd922d0b5ff89e91d34266e8e3863e26 src/transform/model.rs
|
||||||
a4e1d2aa2913587c250f251356431097b76995aee6e8bf9e35c4978a95491de1 src/transform/svg.rs
|
|
||||||
0f53c64f442390ee20a59087a10f8f9ffb58053263e9aa848ddabfae1a6f3f51 src/transform/svg/tests.rs
|
0f53c64f442390ee20a59087a10f8f9ffb58053263e9aa848ddabfae1a6f3f51 src/transform/svg/tests.rs
|
||||||
|
a4e1d2aa2913587c250f251356431097b76995aee6e8bf9e35c4978a95491de1 src/transform/svg.rs
|
||||||
d1f3f53fedae0d8ef69eeee457f7d30ed5a670a1ed4ced60683400ee46680260 src/transform/tests.rs
|
d1f3f53fedae0d8ef69eeee457f7d30ed5a670a1ed4ced60683400ee46680260 src/transform/tests.rs
|
||||||
6146c59f36cf419623747d497b3de685da6c84964df43317bebdcb21deb9ee09 src/update_check.rs
|
|
||||||
c42d000d1d576721af3ffe930589388693001b8113554a7658f6dcbc665b5d1b src/update_check/tests.rs
|
c42d000d1d576721af3ffe930589388693001b8113554a7658f6dcbc665b5d1b src/update_check/tests.rs
|
||||||
92efcdaafb9f5a8514daf63d7fcde29be977d7bdcd90162eda0ce00d6967ffbd src/upstream.rs
|
6146c59f36cf419623747d497b3de685da6c84964df43317bebdcb21deb9ee09 src/update_check.rs
|
||||||
ca695e246bee5389b3757fe8588e48bff5d0ad473bc8588ad4ba7b52c99d7dfa src/upstream/client.rs
|
ca695e246bee5389b3757fe8588e48bff5d0ad473bc8588ad4ba7b52c99d7dfa src/upstream/client.rs
|
||||||
ad29f3fc15c9b627b5d752af5adc9f99ee1364fec2df63f1e4509cb223988efb src/upstream/client_tests.rs
|
56c8a9d1c801be0f41b35c75cb42716c46976951948009c8707122c0a6a1eb58 src/upstream/client_tests.rs
|
||||||
75fef0a488d3f3dabfa03c2eabc5995442dfb3c9a1fde8eb6653a124dda25d43 src/upstream/protocol_tests.rs
|
75fef0a488d3f3dabfa03c2eabc5995442dfb3c9a1fde8eb6653a124dda25d43 src/upstream/protocol_tests.rs
|
||||||
8a112154b9631f62a54584302a3ff6a64e4f177ce79aba678b4cb23e466c6ea3 src/upstream/tests.rs
|
8a112154b9631f62a54584302a3ff6a64e4f177ce79aba678b4cb23e466c6ea3 src/upstream/tests.rs
|
||||||
a6b4905c245a22eafb1aa535d303d0fa24e4353db94e1d67fd42b825bf8c5adb src/user_agent.rs
|
92efcdaafb9f5a8514daf63d7fcde29be977d7bdcd90162eda0ce00d6967ffbd src/upstream.rs
|
||||||
6d7cb73de7d8c6f3780736480f5f81ef08813f4626fd5ed494aca0552cf214a1 src/user_agent/tests.rs
|
6d7cb73de7d8c6f3780736480f5f81ef08813f4626fd5ed494aca0552cf214a1 src/user_agent/tests.rs
|
||||||
3aa1b07cd26d4a5b9e5e94d1d6a712ef1397d827e7f1e8c01f7195b98d2c5f67 src/vhost.rs
|
a6b4905c245a22eafb1aa535d303d0fa24e4353db94e1d67fd42b825bf8c5adb src/user_agent.rs
|
||||||
6678192de56bc10c5cf82bdff8da14eece7685f409592450c07478333aa3b99c src/vhost/error_fallback.rs
|
6678192de56bc10c5cf82bdff8da14eece7685f409592450c07478333aa3b99c src/vhost/error_fallback.rs
|
||||||
63e9fc7f7be78dc3e16a89f015a56a2da6ba3aff0197b70ff48321dfb17529bb src/vhost/model.rs
|
63e9fc7f7be78dc3e16a89f015a56a2da6ba3aff0197b70ff48321dfb17529bb src/vhost/model.rs
|
||||||
35a0aca3eee8d47d1bab27c83d4532cd572fc3e17b5f0d4a8d4515a8f85b3d96 src/vhost/redirect.rs
|
35a0aca3eee8d47d1bab27c83d4532cd572fc3e17b5f0d4a8d4515a8f85b3d96 src/vhost/redirect.rs
|
||||||
9b16b5307e140db97363f56c9fac8319e56df846bb1c919d3bc06091ab6ce69c src/vhost/tests.rs
|
9b16b5307e140db97363f56c9fac8319e56df846bb1c919d3bc06091ab6ce69c src/vhost/tests.rs
|
||||||
b7d0f7f5d0bbd74add3fda9b1308350c4f70f8b6debf979fb977a4f2f659c32f src/vhost/validation.rs
|
b7d0f7f5d0bbd74add3fda9b1308350c4f70f8b6debf979fb977a4f2f659c32f src/vhost/validation.rs
|
||||||
8d1eff4b24f01d137414ef5419f75dd281879228adb70409645b11b3c78c20e9 src/web_server/config.rs
|
3aa1b07cd26d4a5b9e5e94d1d6a712ef1397d827e7f1e8c01f7195b98d2c5f67 src/vhost.rs
|
||||||
9744e8c29ae72a4d9fbc9a76166a97f8292c4c312295ea40d1cb699e03d80a9d src/web_server/config/compile.rs
|
9744e8c29ae72a4d9fbc9a76166a97f8292c4c312295ea40d1cb699e03d80a9d src/web_server/config/compile.rs
|
||||||
bcaa1ae15134d85668b05a88d8abea01e5d188f535ad83cd4459732fd56f2f44 src/web_server/config/model.rs
|
bcaa1ae15134d85668b05a88d8abea01e5d188f535ad83cd4459732fd56f2f44 src/web_server/config/model.rs
|
||||||
a863ad1337fbc353c0f42caea4ac8b3644792e2aa08c37f992b7882b4b8dc6d5 src/web_server/config/validation.rs
|
a863ad1337fbc353c0f42caea4ac8b3644792e2aa08c37f992b7882b4b8dc6d5 src/web_server/config/validation.rs
|
||||||
86c744216d7132d8294a6e90ba9be5fd871646006313d1c62506d40c81db9b12 src/web_server/fastcgi.rs
|
8d1eff4b24f01d137414ef5419f75dd281879228adb70409645b11b3c78c20e9 src/web_server/config.rs
|
||||||
200cba8cb3482e49db73d2c60cb60786175177c7d4be2a566cd281fec7ba7fca src/web_server/fastcgi/protocol.rs
|
200cba8cb3482e49db73d2c60cb60786175177c7d4be2a566cd281fec7ba7fca src/web_server/fastcgi/protocol.rs
|
||||||
cef44ccdf882d84892a64bdbfdc1ba01380fce5e5f86d2829b0f9613f738b964 src/web_server/fastcgi/response.rs
|
cef44ccdf882d84892a64bdbfdc1ba01380fce5e5f86d2829b0f9613f738b964 src/web_server/fastcgi/response.rs
|
||||||
|
86c744216d7132d8294a6e90ba9be5fd871646006313d1c62506d40c81db9b12 src/web_server/fastcgi.rs
|
||||||
e15361622683268c5606a39a9e5db3938e630999767898391226e94ad2e421e8 src/web_server/filesystem.rs
|
e15361622683268c5606a39a9e5db3938e630999767898391226e94ad2e421e8 src/web_server/filesystem.rs
|
||||||
d4fec3682532b0f2d11a0aefcd024f69fb623a39922ddb6c528a2d2de265347d src/web_server/htaccess.rs
|
|
||||||
ca3cd376b313af1ce0ee65081b3327eb213f000d5a215aa4ee6b764de9702126 src/web_server/htaccess/model.rs
|
ca3cd376b313af1ce0ee65081b3327eb213f000d5a215aa4ee6b764de9702126 src/web_server/htaccess/model.rs
|
||||||
76de1d11df75f4a64556b2821fd0a1774d26c9f0ca0e5f2b5fcfad0722d43d47 src/web_server/htaccess/parse.rs
|
76de1d11df75f4a64556b2821fd0a1774d26c9f0ca0e5f2b5fcfad0722d43d47 src/web_server/htaccess/parse.rs
|
||||||
66260d159986d41eab0dfde2cb9f0713fc1cc209c2fb47e9023bd24fd37919e8 src/web_server/htaccess/rewrite.rs
|
66260d159986d41eab0dfde2cb9f0713fc1cc209c2fb47e9023bd24fd37919e8 src/web_server/htaccess/rewrite.rs
|
||||||
8ca74d9cc4470045301f70eb4a9fbabd0dbfe74434429148d2230df9f996c06c src/web_server/htaccess/tests.rs
|
8ca74d9cc4470045301f70eb4a9fbabd0dbfe74434429148d2230df9f996c06c src/web_server/htaccess/tests.rs
|
||||||
|
d4fec3682532b0f2d11a0aefcd024f69fb623a39922ddb6c528a2d2de265347d src/web_server/htaccess.rs
|
||||||
3341264f6e8041ac5a5d3c4b1601a69787386116019b5febc1a5e22bdb1186f9 src/web_server/metrics.rs
|
3341264f6e8041ac5a5d3c4b1601a69787386116019b5febc1a5e22bdb1186f9 src/web_server/metrics.rs
|
||||||
0dbef9b71869fc52cf01e9cb400ffd48fb433ae625383edee6c6c2d735608a76 src/web_server/mod.rs
|
0dbef9b71869fc52cf01e9cb400ffd48fb433ae625383edee6c6c2d735608a76 src/web_server/mod.rs
|
||||||
67ab8bef567452f123c4b9b46a942b39c93f1f765c128edca7ee808ff1c5e304 src/web_server/request.rs
|
67ab8bef567452f123c4b9b46a942b39c93f1f765c128edca7ee808ff1c5e304 src/web_server/request.rs
|
||||||
d98c80663847d6d83073df074ebff65952755415574708abcc153bd8d3adfaa9 src/web_server/response.rs
|
|
||||||
833c9fea744b9649046e1a64d6fc6972fbf6cea640e1943b0db52b7ccfa9faad src/web_server/response/file.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
|
c2e54fd803a10f74490f183e8c030fd0e3e72f5de4e79c55bc393ab57d90ab9a src/web_server/response/file_body/tests.rs
|
||||||
|
ba793a140699956a9aef6bc79b0c731c481af8ab7ac3d816a28695743febcb30 src/web_server/response/file_body.rs
|
||||||
20509f9302b79d3a7be76dda6edaf5711826d3ddf47d19ebe07cb289427ca328 src/web_server/response/headers.rs
|
20509f9302b79d3a7be76dda6edaf5711826d3ddf47d19ebe07cb289427ca328 src/web_server/response/headers.rs
|
||||||
|
d98c80663847d6d83073df074ebff65952755415574708abcc153bd8d3adfaa9 src/web_server/response.rs
|
||||||
305c0109b4f869a99381a142853f9e2205f5c7c4f904b2dfa4643274bfc542af src/web_server/routing.rs
|
305c0109b4f869a99381a142853f9e2205f5c7c4f904b2dfa4643274bfc542af src/web_server/routing.rs
|
||||||
400e1c8aa2fe857d96036a64499fbc3de44c1e3a53811c5b25101fb843359792 src/web_server/security.rs
|
400e1c8aa2fe857d96036a64499fbc3de44c1e3a53811c5b25101fb843359792 src/web_server/security.rs
|
||||||
54cf72a82e023fe46513b9cf3130adfef1cd96c40f790c533016b4825d542e06 src/web_server/serve.rs
|
54cf72a82e023fe46513b9cf3130adfef1cd96c40f790c533016b4825d542e06 src/web_server/serve.rs
|
||||||
|
|||||||
@@ -0,0 +1,81 @@
|
|||||||
|
# RustProxy 0.34.0 HOT HIT follow-up (source candidate)
|
||||||
|
|
||||||
|
## What changed
|
||||||
|
|
||||||
|
The *existing* optimized HOT cache no longer removes/reinserts full entries at
|
||||||
|
HIT time. This follow-up further shortens the critical section without changing
|
||||||
|
cache policy or accepting an approximate eviction algorithm:
|
||||||
|
|
||||||
|
1. Store each published response's immutable headers in `Arc<HeaderMap>`.
|
||||||
|
Snapshot the Arc and the shared `Bytes` body while locked, release the HOT
|
||||||
|
mutex, then clone the headers and build the per-request response. Header
|
||||||
|
cloning is **not eliminated**, because per-request `Age`, `Cache-Status` and
|
||||||
|
transformation annotations must not mutate the stored representation.
|
||||||
|
2. Preserve exact per-HIT sequence, hit count and LRU ordering. Bypass the Vary
|
||||||
|
index traversal for the common direct-key/no-`Vary` representation; continue
|
||||||
|
selecting keyed variants for other representations.
|
||||||
|
3. Replace the per-domain flat pair-key map with a nested ordered map so a
|
||||||
|
known `(scope, domain)` is updated using borrowed keys. Preserve the 4096
|
||||||
|
distinct-domain limit and the dashboard wire format. Update cached-byte
|
||||||
|
accounting without allocating `String` keys.
|
||||||
|
4. When there are no active BAN rules, a cached response does not acquire the
|
||||||
|
BAN mutex or clone any BAN rules. Active rules still perform expiration,
|
||||||
|
matching and removal. Publication/removal of BAN rules updates an atomic
|
||||||
|
count; BAN and PURGE security checks remain enabled.
|
||||||
|
5. Remove repeated full HOT-entry `sweep()` scans. The existing
|
||||||
|
`retention_deadline()` explicitly returns `u64::MAX`: entries beyond their
|
||||||
|
freshness TTL are retained for conditional revalidation and `max-stale`.
|
||||||
|
Capacity/idle eviction and cold-tier GC remain responsible for memory/disk
|
||||||
|
retention. HTTP freshness checks and `Age` are unchanged.
|
||||||
|
6. Avoid allocating the static cache-reason text on each repeat occurrence:
|
||||||
|
previously registered reasons update by borrowed lookup. Recorded dashboard
|
||||||
|
fields, counters and reason labels are unchanged.
|
||||||
|
|
||||||
|
No new configuration, cache key, COLD on-disk format, migration, panel toggle or
|
||||||
|
feature flag was added. Cache query bypass, transformed representations, origin
|
||||||
|
validators, TTL, hot-to-cold demotion, backend selection and `sendfile` behavior
|
||||||
|
are intentionally unchanged.
|
||||||
|
|
||||||
|
## Tests and verification
|
||||||
|
|
||||||
|
Native Rust test file: `src/cache/tests/hot_hit_034_tests.rs`.
|
||||||
|
|
||||||
|
- Multi-threaded HOT access checks monotonic, unique hit counters and bounded
|
||||||
|
LRU/index growth.
|
||||||
|
- Transformed response HIT retains its ETag/extension; changes to the response
|
||||||
|
header map never mutate cached headers. Memory accounting and per-domain
|
||||||
|
saved-byte counters remain exact.
|
||||||
|
- Exact LRU eviction, selective BAN, stale revalidation retention and
|
||||||
|
conditional client `max-stale` are covered.
|
||||||
|
- The manual **ignored** in-process lookup microbenchmark measures the whole
|
||||||
|
`get_hot()` response construction, not network RPS.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./dev.sh check
|
||||||
|
CARGO_INCREMENTAL=0 ./dev.sh test
|
||||||
|
CARGO_INCREMENTAL=0 cargo build --release --locked
|
||||||
|
python3 scripts/tests/cache_hot_034_static_test.py
|
||||||
|
cargo test --release --locked --lib manual_hot_lookup_microbenchmark -- --ignored --nocapture
|
||||||
|
```
|
||||||
|
|
||||||
|
For real HTTP RPS use the supplied process regression and same-host nginx
|
||||||
|
benchmark (`scripts/performance/README.md`) with **identical** configs. The
|
||||||
|
standard nginx comparator benchmark explicitly disables the cache; it cannot
|
||||||
|
measure this HOT-specific improvement. Compare two compiled RustProxy 0.34.0
|
||||||
|
binaries with the same cache-enabled, cache-warmed vhost and fixed no-query URL.
|
||||||
|
Check `X-Cache: HIT`, body SHA-256, exact `Cache-Status`, transform marker, Age,
|
||||||
|
ETag, p95/p99, CPU/request, memory and warm-up/eviction counts while measuring.
|
||||||
|
|
||||||
|
## Remaining performance bottlenecks
|
||||||
|
|
||||||
|
The HOT store still uses a shared mutex to provide exact LRU, per-key
|
||||||
|
generation checks and publication guarantees. Per-response `HeaderMap` cloning
|
||||||
|
is still required and now occurs outside this lock. Sharding the store or
|
||||||
|
making LRU eventually consistent would require a separate, extensively tested
|
||||||
|
cache architecture revision: doing that without compilation and live soak
|
||||||
|
would risk invalidation, accounting, BAN and tier-demotion regressions.
|
||||||
|
|
||||||
|
**Acceptance gate open:** the changed Rust source was not compiled in this
|
||||||
|
environment, new Rust tests were not run and no HOT HIT RPS improvement has been
|
||||||
|
measured. Source-only guards, SQL and upgrade tests do not establish a safe
|
||||||
|
production build.
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
# RustProxy 0.34.0: hot-path throughput revision
|
||||||
|
|
||||||
|
**Status: uncompiled source candidate.** This revision does not change the
|
||||||
|
application version, public API, dashboard controls, cache policy or tuning
|
||||||
|
defaults. It must not be labelled production-ready until the new Rust binary
|
||||||
|
passes compile, unit tests, live regressions and paired performance comparisons.
|
||||||
|
|
||||||
|
## Code changes and intended cost reductions
|
||||||
|
|
||||||
|
| Focus | Change | Kept behavior / risk to verify |
|
||||||
|
|---|---|---|
|
||||||
|
| Per-request identity | Draw a 256-bit nonce from the OS-seeded/reseeded thread-local CSPRNG instead of asking `getrandom` on every request. Preserve SHA-256 of nonce+monotonic sequence and the existing 64-hex ID format. | IDs remain non-predictable. Check ID uniqueness and raw upstream headers. |
|
||||||
|
| Upstream HTTP request target | Compile the validated scheme/authority `http::Uri` once with each immutable backend; parse only the request path+query and rebuild using typed `Uri::from_parts`. | Never accept a client-supplied authority, bypass DNS/address policies or change SNI. Test H1, H2, IPv6, query and percent-encoding. |
|
||||||
|
| Load balancing | Do not clone the member ID string for an existing smooth-WRR scoreboard entry. Continue the previously introduced no-mutex single-member non-cookie path. | Sticky-cookie modes, capacity limits, retry exclusions, health and drain remain unchanged. |
|
||||||
|
| Active health | Use already-compiled `Arc<HealthCheck>` when dispatching probes, avoiding a clone of its path/headers for each scheduled probe. | Same 250-ms supervisor, timeout, enabled/claim gate and health state transitions. |
|
||||||
|
| Per-frame streaming | Capture the leased backend once at first streamed request DATA (response already captured at wrapper construction). Do not take `Exchange.backend` mutex on every upload chunk. | Request/response byte counters, mid-stream failures, idle timeouts and lease lifetime remain active. |
|
||||||
|
| Pool recycling | Preserve exact request-count and elapsed-time recycling checks per request, with the existing independent 250-ms maintenance cycle. The pool factory/connection policy is unchanged. | Exact lifecycle semantics are more important than saving one cheap clock read; tune idle/age limits only after profiling. |
|
||||||
|
| Log history | Move completed `LogEntry` directly into bounded history when there are no live viewers or enabled external sinks, instead of deeply cloning its strings. Continue cloning and delivering to live viewers/sinks when enabled. | Same JSON fields, history size, drop counters, file/Loki/Logstash forwarding. |
|
||||||
|
| Route/HTTP instrumentation | Remove redundant route-ID mutex/write in forwarding and collapse H1/H2 version tallying into one branch. | Route is recorded once before forwarding; H1/H2 counters remain. |
|
||||||
|
|
||||||
|
These changes build on the previous 0.34.0 route-Arc, single-backend LB,
|
||||||
|
conditional retry/fallback-header cloning, atomic exchange flags and cache HOT
|
||||||
|
LRU changes. There are no new UI toggles. Pool defaults remain `max_idle_per_host`
|
||||||
|
4 and `pool_recycle_requests` 25,000; tune these only in separately labelled
|
||||||
|
trials. `sendfile: auto` remains opt-in and applies only to eligible Linux
|
||||||
|
plaintext H1 static WWW responses, not reverse proxy or TLS/H2/H3.
|
||||||
|
|
||||||
|
## Cache transform/query policy
|
||||||
|
|
||||||
|
An enabled `bypass_query` is a deliberate policy: `/theme.css?v=...` is a
|
||||||
|
`BYPASS` even when the origin sends `Cache-Control: public`. Turning the bypass
|
||||||
|
off permits a transformed CSS object to follow `MISS -> HIT` and appear in the
|
||||||
|
cache dashboard. An existing transformed HOT row with hit count and TTL is
|
||||||
|
positive evidence of this. This throughput revision does not modify the
|
||||||
|
cache eligibility logic or discard Age/ETag/Cache-Control headers.
|
||||||
|
|
||||||
|
## Verification already possible here
|
||||||
|
|
||||||
|
- **Old/reproducible reference executable only:** 110 passed, 0 failed, 1 skipped
|
||||||
|
(`compression.codec.zstd` skipped because the optional decoder was missing),
|
||||||
|
from live proxy/policy/cache/transform loopback regression. This does **not**
|
||||||
|
exercise the newly modified Rust source.
|
||||||
|
- **Old/reproducible reference executable only:** query bypass enabled gives
|
||||||
|
`BYPASS -> BYPASS`, disabled gives `MISS -> HIT` and a transformed representation;
|
||||||
|
the older Age regression is also reproducible on this old executable.
|
||||||
|
- Source-only invariants: `scripts/tests/rps_hotpath_034_static_test.py` plus
|
||||||
|
existing route/cache/sendfile checks. SQL migration and upgrade scripts pass.
|
||||||
|
- **Not performed:** Rust compilation or newly added Rust unit tests, live
|
||||||
|
behavior of the optimized binary, HTTP/2 live TLS, comparative RPS, CPU
|
||||||
|
profiling and long-duration memory/health soak. The environment does not
|
||||||
|
include `cargo`, `rustc` or `wrk`. No post-change RPS gain is claimed.
|
||||||
|
|
||||||
|
## Acceptance commands on a Rust-capable Linux host
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./dev.sh check
|
||||||
|
CARGO_INCREMENTAL=0 ./dev.sh test
|
||||||
|
CARGO_INCREMENTAL=0 cargo build --release --locked
|
||||||
|
python3 scripts/tests/rps_hotpath_034_static_test.py
|
||||||
|
python3 scripts/tests/cache_age_transform_034_live.py \
|
||||||
|
--binary "$(realpath target/release/rust-proxy)" \
|
||||||
|
--output /tmp/rustproxy034-cache-after
|
||||||
|
python3 scripts/performance/regression.py \
|
||||||
|
--binary optimized="$(realpath target/release/rust-proxy)" \
|
||||||
|
--out /tmp/rustproxy034-http-regression
|
||||||
|
```
|
||||||
|
|
||||||
|
Run `scripts/performance/benchmark.py` from the documented reproducible
|
||||||
|
before/after/nginx command in `scripts/performance/README.md`. Compare the
|
||||||
|
unchanged old 0.34.0 binary with the newly compiled source, not a baseline
|
||||||
|
with different feature flags. Record RPS at 1,040 B, 64 KiB, 1 MiB, p95/p99,
|
||||||
|
CPU/request, RSS, connection counts, errors and exact response-body hashes.
|
||||||
|
Use `perf record -g -p <proxy-pid>` during a stable request interval and inspect
|
||||||
|
`perf report --stdio` to identify the next true bottleneck.
|
||||||
|
|
||||||
|
Do not interpret Python origin self-tests, source inspections, or speculative
|
||||||
|
Amdahl models as measured RustProxy throughput.
|
||||||
@@ -22,6 +22,26 @@ for compilation and live HTTP, health, capacity, sticky, and H2 retry tests.
|
|||||||
No RPS improvement, corrected nginx gap, or full functional parity has been
|
No RPS improvement, corrected nginx gap, or full functional parity has been
|
||||||
measured for this new revision. Details: `docs/PROXY_HOTPATH_0.34.0.md`.
|
measured for this new revision. Details: `docs/PROXY_HOTPATH_0.34.0.md`.
|
||||||
|
|
||||||
|
## RPS-focused follow-up source revision (not yet compiled)
|
||||||
|
|
||||||
|
See `docs/PROXY_RPS_0.34.0.md` for detailed changes in request IDs, validated
|
||||||
|
upstream URI construction, LB scheduling, probes, streaming byte accounting,
|
||||||
|
unchanged pool generation lifetimes and log-history ownership. Source-only invariants pass.
|
||||||
|
A live test of the PREVIOUS executable (not this source revision) completed
|
||||||
|
110 passing cases, 0 failing cases and 1 skipped optional zstd decoder in the
|
||||||
|
proxy/policy/cache/transform harness. The old executable also confirms query-
|
||||||
|
string bypass is deliberate and reproduces the older Age/TTL bug. The new
|
||||||
|
binary has NOT been built or tested and its RPS gain is unknown.
|
||||||
|
|
||||||
|
## HOT HIT follow-up source revision (not yet compiled)
|
||||||
|
|
||||||
|
See `docs/CACHE_HOTPATH_0.34.0.md`. Response header cloning has moved outside
|
||||||
|
the global HOT lock, and redundant bounded stats key allocation, empty BAN
|
||||||
|
checks and full HOT TTL sweeps were removed. A new Rust concurrency/regression
|
||||||
|
suite and an ignored microbenchmark have been added. Existing COLD and Vary
|
||||||
|
behavior, exact LRU and cache semantics remain. This source has not been built
|
||||||
|
or run under Rust in this environment; no RPS gain is claimed.
|
||||||
|
|
||||||
## Changes and correctness boundaries
|
## Changes and correctness boundaries
|
||||||
|
|
||||||
- Operational per-vhost saves (upstream keepalive/recycling, connection limits,
|
- Operational per-vhost saves (upstream keepalive/recycling, connection limits,
|
||||||
|
|||||||
@@ -18,6 +18,17 @@ shutdown). Treat `--max-idle` tuning and recycles as separately labelled
|
|||||||
experiments rather than mixing them into the primary comparison. There are no
|
experiments rather than mixing them into the primary comparison. There are no
|
||||||
new measured RPS figures in the source candidate.
|
new measured RPS figures in the source candidate.
|
||||||
|
|
||||||
|
## Follow-up RPS candidate on 0.34.0
|
||||||
|
|
||||||
|
`docs/PROXY_RPS_0.34.0.md` tracks the code changes and their regressions.
|
||||||
|
Compile before/after binaries from the two 0.34.0 source revisions and use
|
||||||
|
the paired benchmark below; a live run against the older binary cannot
|
||||||
|
establish a measured RPS improvement for the uncompiled candidate. Keep
|
||||||
|
`max_idle_per_host`, recycling, HTTP1/H2 settings and all application security
|
||||||
|
and logging features equal between runs. Treat any configuration tuning as a
|
||||||
|
separate experiment. Profile the resulting binary with `perf` only after
|
||||||
|
correctness checks pass.
|
||||||
|
|
||||||
## Offline cache-retention model for 0.34.0
|
## Offline cache-retention model for 0.34.0
|
||||||
|
|
||||||
`python3 scripts/performance/simulate_cache_034.py` compares cache invalidation
|
`python3 scripts/performance/simulate_cache_034.py` compares cache invalidation
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ def request(port, path, encoding='identity'):
|
|||||||
'x_cache_hits': headers.get('x-cache-hits'), 'x_cache_resident_age': headers.get('x-cache-resident-age'),
|
'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'),
|
'cache_status': headers.get('cache-status'), 'age': headers.get('age'),
|
||||||
'body': body.decode('utf-8', 'replace'), 'content_length': headers.get('content-length'),
|
'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]}
|
'etag': headers.get('etag'), 'encoding': headers.get('content-encoding'), 'origin_count': COUNTS[path.split('?', 1)[0]]}
|
||||||
|
|
||||||
|
|
||||||
def dash(rust):
|
def dash(rust):
|
||||||
@@ -133,6 +133,25 @@ def run(binary: Path, output: Path, expect_old_age_bug: bool):
|
|||||||
aged_br = find(snapshot, '/aged-br.css')
|
aged_br = find(snapshot, '/aged-br.css')
|
||||||
assert aged_br['transformed'] and aged_br['remaining_ttl_seconds'] >= 86_000, aged_br
|
assert aged_br['transformed'] and aged_br['remaining_ttl_seconds'] >= 86_000, aged_br
|
||||||
|
|
||||||
|
# Query-string bypass is an explicit administrator rule. Even a
|
||||||
|
# transformed CSS with public max-age stays BYPASS while it is ON,
|
||||||
|
# then the *same* URL must become MISS -> HIT after disabling it.
|
||||||
|
# This is not a transform regression: it is a request policy.
|
||||||
|
cfg['cache']['bypass_query'] = True
|
||||||
|
rust.apply(cfg, 'query-bypass-enabled')
|
||||||
|
query_path = '/normal.css?v=transformed-public'
|
||||||
|
before = COUNTS['/normal.css']
|
||||||
|
q_bypass = [request(rust.reverse_port, query_path) for _ in range(2)]
|
||||||
|
assert [row['x_cache'] for row in q_bypass] == ['BYPASS', 'BYPASS'], q_bypass
|
||||||
|
assert COUNTS['/normal.css'] - before == 2, q_bypass
|
||||||
|
cfg['cache']['bypass_query'] = False
|
||||||
|
rust.apply(cfg, 'query-bypass-disabled')
|
||||||
|
q_cached = [request(rust.reverse_port, query_path) for _ in range(2)]
|
||||||
|
assert [row['x_cache'] for row in q_cached] == ['MISS', 'HIT'], q_cached
|
||||||
|
assert q_cached[1]['cache_status'] and 'transformed' in q_cached[1]['cache_status']
|
||||||
|
assert COUNTS['/normal.css'] - before == 3, q_cached
|
||||||
|
outcome['tests'].append({'query_bypass_policy': {'bypass': q_bypass, 'cached': q_cached}})
|
||||||
|
|
||||||
# Operational LB tuning must not invalidate a cached representation.
|
# Operational LB tuning must not invalidate a cached representation.
|
||||||
before = COUNTS['/normal.css']
|
before = COUNTS['/normal.css']
|
||||||
cfg['vhosts'][0]['load_balancing']['keepalive'] = {'max_idle_per_host': 16}
|
cfg['vhosts'][0]['load_balancing']['keepalive'] = {'max_idle_per_host': 16}
|
||||||
|
|||||||
Executable
+30
@@ -0,0 +1,30 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Source-only hot-cache safety guards; NOT a Rust compile, concurrency test or RPS result."""
|
||||||
|
from pathlib import Path
|
||||||
|
ROOT = Path(__file__).resolve().parents[2]
|
||||||
|
read = lambda path: (ROOT / path).read_text()
|
||||||
|
hot = read("src/cache/lookup/hot.rs")
|
||||||
|
entry = read("src/cache/model/cache.rs")
|
||||||
|
model = read("src/cache/model/maintenance.rs")
|
||||||
|
inv = read("src/cache/invalidation/invalidate.rs")
|
||||||
|
dash = read("src/cache/dashboard.rs")
|
||||||
|
assert 'headers: Arc<HeaderMap>' in entry
|
||||||
|
assert 'Arc::clone(&entry.headers)' in hot
|
||||||
|
assert 'drop(store);' in hot
|
||||||
|
assert hot.index('drop(store);\n\n let mut response') < hot.index('headers.as_ref().clone()')
|
||||||
|
assert 'store.saved_body_hit(&ticket.scope, &ticket.domain, body_bytes)' in hot
|
||||||
|
assert 'store.lru.remove(&old_sequence)' in hot and 'store.lru.insert(sequence, storage_key)' in hot
|
||||||
|
assert '.sweep()' not in hot
|
||||||
|
assert 'fn sweep(' not in entry
|
||||||
|
assert 'fn saved_body_hit(' in entry
|
||||||
|
assert 'domains: BTreeMap<String, BTreeMap<String, DomainCounters>>' in entry
|
||||||
|
assert 'if self.ban_rule_count.load(Ordering::Acquire) == 0' in inv
|
||||||
|
assert 'bans.iter().any(|rule| rule.matches_hot' in inv
|
||||||
|
assert 'fn matching_hot_key(' in model and 'entry.vary.is_empty()' in model
|
||||||
|
assert 'store.domain_count = 0' in dash
|
||||||
|
assert 'c.reasons.get_mut(reason)' in dash
|
||||||
|
assert 'include!("tests/hot_hit_034_tests.rs")' in read('src/cache/tests.rs')
|
||||||
|
for path in (ROOT / 'src').rglob('*.rs'):
|
||||||
|
if '/tests/' not in path.as_posix() and path.name != 'tests.rs':
|
||||||
|
assert len(path.read_text().splitlines()) <= 500, path
|
||||||
|
print('PASS HOT path static invariants (no Rust compilation or throughput claim)')
|
||||||
@@ -28,7 +28,8 @@ assert "scope_revision: draft.scope_revision" in read("src/cache/cold/worker.rs"
|
|||||||
body = read("src/proxy/body.rs")
|
body = read("src/proxy/body.rs")
|
||||||
assert "response_backend: Option<Arc<crate::balance::Lease>>" in body
|
assert "response_backend: Option<Arc<crate::balance::Lease>>" in body
|
||||||
assert "lease.bytes(count, false);" in body
|
assert "lease.bytes(count, false);" in body
|
||||||
assert "exchange.backend_bytes(count, true)" in body
|
assert "request_backend: Option<Arc<crate::balance::Lease>>" in body
|
||||||
|
assert "lease.bytes(count, true);" in body
|
||||||
assert "cold_scope_fingerprint_preserves_unmodified_vhost" in read("src/cache/tests/cold_tier_tests.rs")
|
assert "cold_scope_fingerprint_preserves_unmodified_vhost" in read("src/cache/tests/cold_tier_tests.rs")
|
||||||
assert "stale_snapshot_cannot_issue_cache_ticket" in read("src/cache/tests/scope_tests.rs")
|
assert "stale_snapshot_cannot_issue_cache_ticket" in read("src/cache/tests/scope_tests.rs")
|
||||||
for file in (root / 'src').rglob('*.rs'):
|
for file in (root / 'src').rglob('*.rs'):
|
||||||
|
|||||||
@@ -0,0 +1,99 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Source invariants for 0.34.0 RPS optimizations (NOT a Rust build or RPS test).
|
||||||
|
|
||||||
|
These guards reject accidental removal of important branch/safety conditions.
|
||||||
|
They must be paired with ``cargo test`` and live black-box HTTP acceptance.
|
||||||
|
"""
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[2]
|
||||||
|
|
||||||
|
|
||||||
|
def source(path):
|
||||||
|
return (ROOT / path).read_text(encoding="utf-8")
|
||||||
|
|
||||||
|
|
||||||
|
# Random request identifiers retain CSPRNG entropy, SHA-256, format and sequence.
|
||||||
|
identifier = source("src/proxy/request_id.rs")
|
||||||
|
assert "rand::random()" in identifier
|
||||||
|
assert "hash.update(sequence.to_be_bytes());" in identifier
|
||||||
|
assert "hash.update(nonce);" in identifier
|
||||||
|
assert "request_id_hex(&hash.finalize())" in identifier
|
||||||
|
assert "SysRng.try_fill_bytes" not in identifier
|
||||||
|
|
||||||
|
# Compiled/validated target authority survives request URI construction.
|
||||||
|
config = source("src/config/backend.rs")
|
||||||
|
model = source("src/config/model.rs")
|
||||||
|
request = source("src/proxy/types.rs")
|
||||||
|
assert "let request_origin_uri: http::Uri = request_origin.parse()?;" in config
|
||||||
|
assert "request_origin_uri," in config
|
||||||
|
assert "pub request_origin_uri: http::Uri," in model
|
||||||
|
assert "let path: http::uri::PathAndQuery = suffix.parse().ok()?;" in request
|
||||||
|
assert "let mut parts = backend.request_origin_uri.clone().into_parts();" in request
|
||||||
|
assert "parts.path_and_query = Some(path);" in request
|
||||||
|
assert "Uri::from_parts(parts).ok()" in request
|
||||||
|
|
||||||
|
# No new unbounded caches or disabled LB safety gates.
|
||||||
|
pool = source("src/balance/pool_core.rs")
|
||||||
|
assert "if self.members.len() == 1 && !self.cookie_affinity()" in pool
|
||||||
|
assert "try_acquire_active(member.definition.max_concurrent_requests)" in pool
|
||||||
|
assert "m.state.healthy()" in pool
|
||||||
|
assert "scheduling.get_mut(member.definition.id.as_str())" in pool
|
||||||
|
assert "scheduling.entry(member.definition.id.clone())" in pool
|
||||||
|
health = source("src/balance/lease_runtime.rs")
|
||||||
|
assert "async fn probe(member: Arc<Member>, settings: Arc<HealthCheck>)" in health
|
||||||
|
assert "checks.spawn(probe(Arc::clone(member), health.clone()))" in health
|
||||||
|
assert "tokio::time::timeout" in health
|
||||||
|
|
||||||
|
# Configurable keep-alive policy, exact recycle-request threshold and age backup.
|
||||||
|
upstream = source("src/upstream/client.rs")
|
||||||
|
assert "self.current.load_full()" in upstream
|
||||||
|
assert "request_due || age_due" in upstream
|
||||||
|
assert "let now = monotonic_millis();" in upstream
|
||||||
|
assert "let age_ms = now.saturating_sub(self.generation_started_ms.load(Ordering::Relaxed));" in upstream
|
||||||
|
assert "fn maintain_rotation_at(" in upstream
|
||||||
|
assert "self.factory.keepalive.pool_recycle_requests" in upstream
|
||||||
|
assert "self.factory.keepalive.pool_recycle_seconds" in upstream
|
||||||
|
assert "pool_max_idle_per_host(if keepalive.enabled" in upstream
|
||||||
|
assert "retry_canceled_requests(false)" in upstream
|
||||||
|
assert "observe_protocol" in upstream
|
||||||
|
|
||||||
|
# Request/response streamed payloads retain accounting and timeout/cancellation.
|
||||||
|
body = source("src/proxy/body.rs")
|
||||||
|
assert "request_backend: Option<Arc<crate::balance::Lease>>" in body
|
||||||
|
assert "this.request_backend = exchange.backend" in body
|
||||||
|
assert "lease.bytes(count, true)" in body
|
||||||
|
assert "lease.bytes(count, false)" in body
|
||||||
|
assert "exchange.request_bytes.fetch_add(count" in body
|
||||||
|
assert "exchange.response_bytes.fetch_add(count" in body
|
||||||
|
assert "get_or_insert_with(|| Box::pin(sleep_until(this.deadline)))" in body
|
||||||
|
assert "this.finish();" in body
|
||||||
|
|
||||||
|
# Persist history and preserve live streaming/sink drop accounting.
|
||||||
|
logs = source("src/logging/format.rs")
|
||||||
|
assert "let has_viewers = self.live.receiver_count() != 0;" in logs
|
||||||
|
assert "let has_sink = self.settings.load().enabled();" in logs
|
||||||
|
assert "external.take().expect(\"entry\")" in logs
|
||||||
|
assert "self.live.send(entry.clone())" in logs
|
||||||
|
assert "self.sink.try_send(entry)" in logs
|
||||||
|
assert "self.sink_dropped.fetch_add(1" in logs
|
||||||
|
|
||||||
|
# Never weaken routing, identity, HTTP version and cache eligibility while tuning.
|
||||||
|
route = source("src/proxy/forward/route_cache.rs")
|
||||||
|
assert "admin_session_passthrough" in route
|
||||||
|
assert "cache_plan.request_policy" in route
|
||||||
|
assert "exchange.set_cache_enabled" in route
|
||||||
|
assert "exchange.set_transform_enabled" in route
|
||||||
|
assert "upstream_uri(&backend, &origin_suffix)" in route
|
||||||
|
assert "headers::strip_hop_by_hop" in route
|
||||||
|
assert "pool.select_wait(context.client_ip" in route or ".select_wait(context.client_ip" in route
|
||||||
|
assert "pool.select_member_wait(id)" in route
|
||||||
|
assert "max_idle_per_host: 4" in source("src/balance/model.rs")
|
||||||
|
assert "pool_recycle_requests: 25_000" in source("src/balance/model.rs")
|
||||||
|
assert 'version = "0.34.0"' in source("Cargo.toml")
|
||||||
|
|
||||||
|
for file in (ROOT / "src").rglob("*.rs"):
|
||||||
|
if "/tests/" in file.as_posix() or file.name == "tests.rs":
|
||||||
|
continue
|
||||||
|
assert len(file.read_text(encoding="utf-8").splitlines()) <= 500, file
|
||||||
|
print("PASS RPS hot-path source invariants (STATIC ONLY; new binary not compiled)")
|
||||||
@@ -296,7 +296,7 @@ impl Pool {
|
|||||||
text
|
text
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async fn probe(member: Arc<Member>, settings: HealthCheck) {
|
async fn probe(member: Arc<Member>, settings: Arc<HealthCheck>) {
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
let result = tokio::time::timeout(Duration::from_millis(settings.timeout_ms), async {
|
let result = tokio::time::timeout(Duration::from_millis(settings.timeout_ms), async {
|
||||||
match settings.mode {
|
match settings.mode {
|
||||||
@@ -388,8 +388,12 @@ pub async fn health_loop(app: Weak<crate::runtime::App>, shutdown: CancellationT
|
|||||||
let snapshot = app.config.load_full();
|
let snapshot = app.config.load_full();
|
||||||
// Own an Arc for each candidate. JoinSet tasks require an
|
// Own an Arc for each candidate. JoinSet tasks require an
|
||||||
// owned, 'static member rather than a reference into snapshot.
|
// owned, 'static member rather than a reference into snapshot.
|
||||||
|
// Health settings were already compiled into each member.
|
||||||
|
// Reuse the immutable Arc instead of cloning each HealthCheck
|
||||||
|
// and recalculating per-member overrides on every 250ms tick.
|
||||||
let members: Vec<_> = snapshot.pools.iter().flat_map(|pool|
|
let members: Vec<_> = snapshot.pools.iter().flat_map(|pool|
|
||||||
pool.members.iter().map(move |member| (Arc::clone(member), pool.settings.health_for(&member.definition)))).collect();
|
pool.members.iter().map(|member|
|
||||||
|
(Arc::clone(member), Arc::clone(&member.health_settings)))).collect();
|
||||||
for (member, _) in &members {
|
for (member, _) in &members {
|
||||||
member.state.sample_traffic();
|
member.state.sample_traffic();
|
||||||
// Time-based pool recycling must not depend on receiving a
|
// Time-based pool recycling must not depend on receiving a
|
||||||
|
|||||||
@@ -279,9 +279,13 @@ impl Pool {
|
|||||||
let weight = member
|
let weight = member
|
||||||
.state
|
.state
|
||||||
.weight(member.definition.weight, self.settings.slow_start_seconds);
|
.weight(member.definition.weight, self.settings.slow_start_seconds);
|
||||||
let current = scheduling
|
let current = if let Some(current) =
|
||||||
.entry(member.definition.id.clone())
|
scheduling.get_mut(member.definition.id.as_str())
|
||||||
.or_insert(0.0);
|
{
|
||||||
|
current
|
||||||
|
} else {
|
||||||
|
scheduling.entry(member.definition.id.clone()).or_insert(0.0)
|
||||||
|
};
|
||||||
*current += weight;
|
*current += weight;
|
||||||
total += weight;
|
total += weight;
|
||||||
if *current > best {
|
if *current > best {
|
||||||
|
|||||||
Vendored
+14
-13
@@ -6,9 +6,6 @@ impl Cache {
|
|||||||
.unwrap_or_else(|e| e.into_inner())
|
.unwrap_or_else(|e| e.into_inner())
|
||||||
.clone();
|
.clone();
|
||||||
let mut store = self.store.lock().unwrap_or_else(|e| e.into_inner());
|
let mut store = self.store.lock().unwrap_or_else(|e| e.into_inner());
|
||||||
self.counters
|
|
||||||
.expired
|
|
||||||
.fetch_add(store.sweep() as u64, Ordering::Relaxed);
|
|
||||||
let n = |value: &AtomicU64| value.load(Ordering::Relaxed);
|
let n = |value: &AtomicU64| value.load(Ordering::Relaxed);
|
||||||
let hits = n(&self.counters.hits);
|
let hits = n(&self.counters.hits);
|
||||||
let misses = n(&self.counters.misses);
|
let misses = n(&self.counters.misses);
|
||||||
@@ -180,6 +177,7 @@ impl Cache {
|
|||||||
store.revision = revision;
|
store.revision = revision;
|
||||||
self.revision.store(revision, Ordering::Relaxed);
|
self.revision.store(revision, Ordering::Relaxed);
|
||||||
store.domains.clear();
|
store.domains.clear();
|
||||||
|
store.domain_count = 0;
|
||||||
}
|
}
|
||||||
drop(store);
|
drop(store);
|
||||||
self.cancel_all_fill_flights();
|
self.cancel_all_fill_flights();
|
||||||
@@ -247,9 +245,6 @@ impl Cache {
|
|||||||
}
|
}
|
||||||
pub fn scope_view(&self, scope: &str) -> ScopeView {
|
pub fn scope_view(&self, scope: &str) -> ScopeView {
|
||||||
let mut store = self.store.lock().unwrap_or_else(|e| e.into_inner());
|
let mut store = self.store.lock().unwrap_or_else(|e| e.into_inner());
|
||||||
self.counters
|
|
||||||
.expired
|
|
||||||
.fetch_add(store.sweep() as u64, Ordering::Relaxed);
|
|
||||||
let mut view = ScopeView {
|
let mut view = ScopeView {
|
||||||
entries: 0,
|
entries: 0,
|
||||||
resident_bytes: 0,
|
resident_bytes: 0,
|
||||||
@@ -276,26 +271,32 @@ impl Cache {
|
|||||||
"MISS" => c.misses += 1,
|
"MISS" => c.misses += 1,
|
||||||
_ => c.bypasses += 1,
|
_ => c.bypasses += 1,
|
||||||
}
|
}
|
||||||
*c.reasons.entry(reason.into()).or_default() += 1;
|
if let Some(count) = c.reasons.get_mut(reason) {
|
||||||
|
*count = count.saturating_add(1);
|
||||||
|
} else {
|
||||||
|
c.reasons.insert(reason.to_owned(), 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn record_reason(&self, scope: &str, domain: &str, reason: &'static str) {
|
pub fn record_reason(&self, scope: &str, domain: &str, reason: &'static str) {
|
||||||
let mut store = self.store.lock().unwrap_or_else(|e| e.into_inner());
|
let mut store = self.store.lock().unwrap_or_else(|e| e.into_inner());
|
||||||
if let Some(c) = store.domain(scope, domain) {
|
if let Some(c) = store.domain(scope, domain) {
|
||||||
*c.reasons.entry(reason.into()).or_default() += 1;
|
if let Some(count) = c.reasons.get_mut(reason) {
|
||||||
|
*count = count.saturating_add(1);
|
||||||
|
} else {
|
||||||
|
c.reasons.insert(reason.to_owned(), 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn dashboard(&self, scope: Option<&str>, offset: usize, limit: usize) -> Dashboard {
|
pub fn dashboard(&self, scope: Option<&str>, offset: usize, limit: usize) -> Dashboard {
|
||||||
let mut store = self.store.lock().unwrap_or_else(|e| e.into_inner());
|
let mut store = self.store.lock().unwrap_or_else(|e| e.into_inner());
|
||||||
self.counters
|
|
||||||
.expired
|
|
||||||
.fetch_add(store.sweep() as u64, Ordering::Relaxed);
|
|
||||||
let revision = store.revision;
|
let revision = store.revision;
|
||||||
let mut groups: BTreeMap<(String, String), DomainView> = store
|
let mut groups: BTreeMap<(String, String), DomainView> = store
|
||||||
.domains
|
.domains
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|((vhost, _), _)| scope.is_none_or(|s| s == vhost))
|
.filter(|(vhost, _)| scope.is_none_or(|s| s == vhost.as_str()))
|
||||||
.map(|((vhost, domain), counters)| {
|
.flat_map(|(vhost, domains)| domains.iter().map(move |(domain, counters)| (vhost, domain, counters)))
|
||||||
|
.map(|(vhost, domain, counters)| {
|
||||||
(
|
(
|
||||||
(vhost.clone(), domain.clone()),
|
(vhost.clone(), domain.clone()),
|
||||||
DomainView {
|
DomainView {
|
||||||
|
|||||||
Vendored
+1
-1
@@ -160,7 +160,7 @@ impl Candidate {
|
|||||||
created_at,
|
created_at,
|
||||||
body,
|
body,
|
||||||
body_allocated: body_allocation,
|
body_allocated: body_allocation,
|
||||||
headers: self.headers,
|
headers: Arc::new(self.headers),
|
||||||
received: self.plan.received,
|
received: self.plan.received,
|
||||||
last_access: Instant::now(),
|
last_access: Instant::now(),
|
||||||
resident_since: Instant::now(),
|
resident_since: Instant::now(),
|
||||||
|
|||||||
Vendored
+27
-11
@@ -1,17 +1,24 @@
|
|||||||
impl Cache {
|
impl Cache {
|
||||||
fn active_bans(&self) -> Vec<BanRule> {
|
fn active_bans(&self) -> Vec<BanRule> {
|
||||||
|
if self.ban_rule_count.load(Ordering::Acquire) == 0 {
|
||||||
|
return Vec::new();
|
||||||
|
}
|
||||||
let now = SystemTime::now();
|
let now = SystemTime::now();
|
||||||
let mut bans = self.bans.lock().unwrap_or_else(|e| e.into_inner());
|
let mut bans = self.bans.lock().unwrap_or_else(|e| e.into_inner());
|
||||||
bans.retain(|rule| !rule.expired(now));
|
bans.retain(|rule| !rule.expired(now));
|
||||||
|
self.ban_rule_count.store(bans.len() as u64, Ordering::Release);
|
||||||
bans.clone()
|
bans.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hot_entry_banned(&self, key: &Key, entry: &Entry) -> bool {
|
fn hot_entry_banned(&self, key: &Key, entry: &Entry) -> bool {
|
||||||
|
if self.ban_rule_count.load(Ordering::Acquire) == 0 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
let now = SystemTime::now();
|
let now = SystemTime::now();
|
||||||
let banned = self
|
let mut bans = self.bans.lock().unwrap_or_else(|e| e.into_inner());
|
||||||
.active_bans()
|
bans.retain(|rule| !rule.expired(now));
|
||||||
.iter()
|
self.ban_rule_count.store(bans.len() as u64, Ordering::Release);
|
||||||
.any(|rule| rule.matches_hot(key, entry, now));
|
let banned = bans.iter().any(|rule| rule.matches_hot(key, entry, now));
|
||||||
if banned {
|
if banned {
|
||||||
self.counters.ban_matches.fetch_add(1, Ordering::Relaxed);
|
self.counters.ban_matches.fetch_add(1, Ordering::Relaxed);
|
||||||
}
|
}
|
||||||
@@ -19,11 +26,14 @@ impl Cache {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn cold_entry_banned(&self, key: &Key, entry: &ColdEntry) -> bool {
|
fn cold_entry_banned(&self, key: &Key, entry: &ColdEntry) -> bool {
|
||||||
|
if self.ban_rule_count.load(Ordering::Acquire) == 0 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
let now = SystemTime::now();
|
let now = SystemTime::now();
|
||||||
let banned = self
|
let mut bans = self.bans.lock().unwrap_or_else(|e| e.into_inner());
|
||||||
.active_bans()
|
bans.retain(|rule| !rule.expired(now));
|
||||||
.iter()
|
self.ban_rule_count.store(bans.len() as u64, Ordering::Release);
|
||||||
.any(|rule| rule.matches_cold(key, entry, now));
|
let banned = bans.iter().any(|rule| rule.matches_cold(key, entry, now));
|
||||||
if banned {
|
if banned {
|
||||||
self.counters.ban_matches.fetch_add(1, Ordering::Relaxed);
|
self.counters.ban_matches.fetch_add(1, Ordering::Relaxed);
|
||||||
}
|
}
|
||||||
@@ -31,10 +41,14 @@ impl Cache {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn entry_banned_before_insert(&self, key: &Key, entry: &Entry) -> bool {
|
fn entry_banned_before_insert(&self, key: &Key, entry: &Entry) -> bool {
|
||||||
|
if self.ban_rule_count.load(Ordering::Acquire) == 0 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
let now = SystemTime::now();
|
let now = SystemTime::now();
|
||||||
self.active_bans()
|
let mut bans = self.bans.lock().unwrap_or_else(|e| e.into_inner());
|
||||||
.iter()
|
bans.retain(|rule| !rule.expired(now));
|
||||||
.any(|rule| rule.matches_hot(key, entry, now))
|
self.ban_rule_count.store(bans.len() as u64, Ordering::Release);
|
||||||
|
bans.iter().any(|rule| rule.matches_hot(key, entry, now))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bans(&self) -> Vec<BanView> {
|
pub fn bans(&self) -> Vec<BanView> {
|
||||||
@@ -46,6 +60,7 @@ impl Cache {
|
|||||||
let before = bans.len();
|
let before = bans.len();
|
||||||
bans.retain(|rule| rule.id != id);
|
bans.retain(|rule| rule.id != id);
|
||||||
let removed = bans.len() != before;
|
let removed = bans.len() != before;
|
||||||
|
self.ban_rule_count.store(bans.len() as u64, Ordering::Release);
|
||||||
if removed {
|
if removed {
|
||||||
self.counters.bans_removed.fetch_add(1, Ordering::Relaxed);
|
self.counters.bans_removed.fetch_add(1, Ordering::Relaxed);
|
||||||
}
|
}
|
||||||
@@ -82,6 +97,7 @@ impl Cache {
|
|||||||
created_at: now,
|
created_at: now,
|
||||||
expires_at: now.checked_add(Duration::from_secs(ttl)).unwrap_or(now),
|
expires_at: now.checked_add(Duration::from_secs(ttl)).unwrap_or(now),
|
||||||
});
|
});
|
||||||
|
self.ban_rule_count.store(bans.len() as u64, Ordering::Release);
|
||||||
self.counters.bans_created.fetch_add(1, Ordering::Relaxed);
|
self.counters.bans_created.fetch_add(1, Ordering::Relaxed);
|
||||||
Ok(InvalidationResult {
|
Ok(InvalidationResult {
|
||||||
operation: request.operation,
|
operation: request.operation,
|
||||||
|
|||||||
Vendored
+2
@@ -25,6 +25,7 @@ impl Cache {
|
|||||||
fill_flight_sequence: AtomicU64::new(0),
|
fill_flight_sequence: AtomicU64::new(0),
|
||||||
collapse_waiters: AtomicU64::new(0),
|
collapse_waiters: AtomicU64::new(0),
|
||||||
bans: Mutex::new(Vec::new()),
|
bans: Mutex::new(Vec::new()),
|
||||||
|
ban_rule_count: AtomicU64::new(0),
|
||||||
ban_sequence: AtomicU64::new(0),
|
ban_sequence: AtomicU64::new(0),
|
||||||
proactive_scheduled_keys: Mutex::new(HashSet::new()),
|
proactive_scheduled_keys: Mutex::new(HashSet::new()),
|
||||||
proactive_inflight: AtomicU64::new(0),
|
proactive_inflight: AtomicU64::new(0),
|
||||||
@@ -75,6 +76,7 @@ impl Cache {
|
|||||||
fill_flight_sequence: AtomicU64::new(0),
|
fill_flight_sequence: AtomicU64::new(0),
|
||||||
collapse_waiters: AtomicU64::new(0),
|
collapse_waiters: AtomicU64::new(0),
|
||||||
bans: Mutex::new(Vec::new()),
|
bans: Mutex::new(Vec::new()),
|
||||||
|
ban_rule_count: AtomicU64::new(0),
|
||||||
ban_sequence: AtomicU64::new(0),
|
ban_sequence: AtomicU64::new(0),
|
||||||
proactive_scheduled_keys: Mutex::new(HashSet::new()),
|
proactive_scheduled_keys: Mutex::new(HashSet::new()),
|
||||||
proactive_inflight: AtomicU64::new(0),
|
proactive_inflight: AtomicU64::new(0),
|
||||||
|
|||||||
Vendored
+49
-57
@@ -1,29 +1,20 @@
|
|||||||
impl Cache {
|
impl Cache {
|
||||||
fn get_hot(&self, ticket: &Ticket, count_miss: bool) -> Option<Hit> {
|
fn get_hot(&self, ticket: &Ticket, count_miss: bool) -> Option<Hit> {
|
||||||
|
// Only metadata, hit counters and exact LRU ordering require the store
|
||||||
|
// mutex. Materializing an HTTP response may allocate (headers, Body,
|
||||||
|
// Age formatting) and must be done *after* dropping that mutex.
|
||||||
let mut store = self.store.lock().unwrap_or_else(|e| e.into_inner());
|
let mut store = self.store.lock().unwrap_or_else(|e| e.into_inner());
|
||||||
let expired = store.sweep();
|
|
||||||
self.counters
|
|
||||||
.expired
|
|
||||||
.fetch_add(expired as u64, Ordering::Relaxed);
|
|
||||||
if store.revision != ticket.revision
|
if store.revision != ticket.revision
|
||||||
|| store.generation != ticket.generation
|
|| store.generation != ticket.generation
|
||||||
|| store
|
|| store.scope_generations.get(&ticket.scope).copied().unwrap_or(0)
|
||||||
.scope_generations
|
|
||||||
.get(&ticket.scope)
|
|
||||||
.copied()
|
|
||||||
.unwrap_or(0)
|
|
||||||
!= ticket.scope_generation
|
!= ticket.scope_generation
|
||||||
|| store.key_generations.get(&ticket.key).copied().unwrap_or(0) != ticket.key_generation
|
|| store.key_generations.get(&ticket.key).copied().unwrap_or(0)
|
||||||
|
!= ticket.key_generation
|
||||||
{
|
{
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
if let Some(storage_key) = matching_hot_key(&store, ticket) {
|
if let Some(storage_key) = matching_hot_key(&store, ticket) {
|
||||||
// Don't remove and reinsert the entire Entry + variant index on
|
let banned = store.entries.get(&storage_key)
|
||||||
// every HOT hit. A cache hit changes only the LRU sequence, hits
|
|
||||||
// counter, and last-access clock; body/headers remain immutable.
|
|
||||||
let banned = store
|
|
||||||
.entries
|
|
||||||
.get(&storage_key)
|
|
||||||
.is_some_and(|entry| self.hot_entry_banned(&storage_key, entry));
|
.is_some_and(|entry| self.hot_entry_banned(&storage_key, entry));
|
||||||
if banned {
|
if banned {
|
||||||
store.remove(&storage_key);
|
store.remove(&storage_key);
|
||||||
@@ -34,14 +25,9 @@ impl Cache {
|
|||||||
release_allocator_memory();
|
release_allocator_memory();
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let Some(entry) = store.entries.get(&storage_key) else {
|
let entry = store.entries.get(&storage_key)?;
|
||||||
return None;
|
|
||||||
};
|
|
||||||
let resident_age_seconds = hot_resident_age(entry).as_secs();
|
let resident_age_seconds = hot_resident_age(entry).as_secs();
|
||||||
let age = entry
|
let age = entry.initial_age.saturating_add(entry.received.elapsed()).as_secs();
|
||||||
.initial_age
|
|
||||||
.saturating_add(entry.received.elapsed())
|
|
||||||
.as_secs();
|
|
||||||
let state = cache_state(
|
let state = cache_state(
|
||||||
age,
|
age,
|
||||||
entry.ttl,
|
entry.ttl,
|
||||||
@@ -53,48 +39,54 @@ impl Cache {
|
|||||||
);
|
);
|
||||||
if state.servable() {
|
if state.servable() {
|
||||||
let sequence = store.next_sequence();
|
let sequence = store.next_sequence();
|
||||||
let (old_sequence, scope, domain, body_bytes, result) = {
|
let (old_sequence, headers, body, hits, transformed, skip_compression,
|
||||||
|
remaining_ttl, body_bytes) = {
|
||||||
let entry = store.entries.get_mut(&storage_key)?;
|
let entry = store.entries.get_mut(&storage_key)?;
|
||||||
let old_sequence = entry.sequence;
|
let old_sequence = entry.sequence;
|
||||||
entry.hits = entry.hits.saturating_add(1);
|
entry.hits = entry.hits.saturating_add(1);
|
||||||
entry.last_access = Instant::now();
|
entry.last_access = Instant::now();
|
||||||
entry.sequence = sequence;
|
entry.sequence = sequence;
|
||||||
let mut response = Response::new(Body::from(entry.body.clone()));
|
(
|
||||||
*response.headers_mut() = entry.headers.clone();
|
old_sequence,
|
||||||
if entry.transformed {
|
Arc::clone(&entry.headers),
|
||||||
response
|
entry.body.clone(),
|
||||||
.extensions_mut()
|
entry.hits,
|
||||||
.insert(crate::transform::CachedTransformed);
|
entry.transformed,
|
||||||
}
|
entry.skip_compression,
|
||||||
if entry.skip_compression {
|
entry.ttl.saturating_sub(age),
|
||||||
response.extensions_mut().insert(crate::compression::Skip);
|
entry.body.len(),
|
||||||
}
|
)
|
||||||
response.headers_mut().insert(
|
|
||||||
"age",
|
|
||||||
HeaderValue::from_str(&age.to_string()).expect("integer header"),
|
|
||||||
);
|
|
||||||
let result = Hit {
|
|
||||||
response,
|
|
||||||
body: entry.body.clone(),
|
|
||||||
hits: entry.hits,
|
|
||||||
transformed: entry.transformed,
|
|
||||||
remaining_ttl: entry.ttl.saturating_sub(age),
|
|
||||||
resident_age_seconds,
|
|
||||||
stale: state.stale(),
|
|
||||||
background_revalidate: state.background_revalidate(),
|
|
||||||
};
|
|
||||||
(old_sequence, entry.scope.clone(), entry.domain.clone(), entry.body.len(), result)
|
|
||||||
};
|
};
|
||||||
store.lru.remove(&old_sequence);
|
store.lru.remove(&old_sequence);
|
||||||
store.lru.insert(sequence, storage_key);
|
store.lru.insert(sequence, storage_key);
|
||||||
// `store.bytes`, `store.logical_bytes` and the Vary schema index
|
// Preserve the exact LRU and domain-byte counters, without
|
||||||
// did not change. In particular, this path does not allocate a
|
// allocating a replacement variant index or String keys.
|
||||||
// replacement variants Vec for every response.
|
store.saved_body_hit(&ticket.scope, &ticket.domain, body_bytes);
|
||||||
if let Some(counter) = store.domain(&scope, &domain) {
|
|
||||||
counter.saved_body_bytes = counter.saved_body_bytes.saturating_add(body_bytes as u64);
|
|
||||||
}
|
|
||||||
self.counters.hits.fetch_add(1, Ordering::Relaxed);
|
self.counters.hits.fetch_add(1, Ordering::Relaxed);
|
||||||
return Some(result);
|
drop(store);
|
||||||
|
|
||||||
|
let mut response = Response::new(Body::from(body.clone()));
|
||||||
|
*response.headers_mut() = headers.as_ref().clone();
|
||||||
|
if transformed {
|
||||||
|
response.extensions_mut().insert(crate::transform::CachedTransformed);
|
||||||
|
}
|
||||||
|
if skip_compression {
|
||||||
|
response.extensions_mut().insert(crate::compression::Skip);
|
||||||
|
}
|
||||||
|
response.headers_mut().insert(
|
||||||
|
"age",
|
||||||
|
HeaderValue::from_str(&age.to_string()).expect("integer header"),
|
||||||
|
);
|
||||||
|
return Some(Hit {
|
||||||
|
response,
|
||||||
|
body,
|
||||||
|
hits,
|
||||||
|
transformed,
|
||||||
|
remaining_ttl,
|
||||||
|
resident_age_seconds,
|
||||||
|
stale: state.stale(),
|
||||||
|
background_revalidate: state.background_revalidate(),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if count_miss {
|
if count_miss {
|
||||||
@@ -243,7 +235,7 @@ impl Cache {
|
|||||||
target: entry.target.clone(),
|
target: entry.target.clone(),
|
||||||
tags: entry.tags.clone(),
|
tags: entry.tags.clone(),
|
||||||
created_at: entry.created_at,
|
created_at: entry.created_at,
|
||||||
headers: metadata.headers.clone(),
|
headers: Arc::new(metadata.headers.clone()),
|
||||||
body: body.clone(),
|
body: body.clone(),
|
||||||
body_allocated,
|
body_allocated,
|
||||||
received: Instant::now(),
|
received: Instant::now(),
|
||||||
|
|||||||
Vendored
-3
@@ -51,9 +51,6 @@ impl Cache {
|
|||||||
store.remove(&key);
|
store.remove(&key);
|
||||||
}
|
}
|
||||||
store.remove(&storage_key);
|
store.remove(&storage_key);
|
||||||
self.counters
|
|
||||||
.expired
|
|
||||||
.fetch_add(store.sweep() as u64, Ordering::Relaxed);
|
|
||||||
let revision = store.revision;
|
let revision = store.revision;
|
||||||
let generation = store.generation;
|
let generation = store.generation;
|
||||||
let mut released_hot = false;
|
let mut released_hot = false;
|
||||||
|
|||||||
Vendored
+1
-1
@@ -77,7 +77,7 @@ impl Cache {
|
|||||||
target: ticket.target.clone(),
|
target: ticket.target.clone(),
|
||||||
tags,
|
tags,
|
||||||
created_at: ticket.created_at,
|
created_at: ticket.created_at,
|
||||||
headers: headers.clone(),
|
headers: Arc::new(headers.clone()),
|
||||||
body: cached.body.clone(),
|
body: cached.body.clone(),
|
||||||
body_allocated: cached.body_allocated,
|
body_allocated: cached.body_allocated,
|
||||||
received: plan.received,
|
received: plan.received,
|
||||||
|
|||||||
Vendored
+20
-32
@@ -111,7 +111,7 @@ struct Entry {
|
|||||||
target: String,
|
target: String,
|
||||||
tags: Vec<String>,
|
tags: Vec<String>,
|
||||||
created_at: SystemTime,
|
created_at: SystemTime,
|
||||||
headers: HeaderMap,
|
headers: Arc<HeaderMap>,
|
||||||
body: Bytes,
|
body: Bytes,
|
||||||
/// Backing allocation retained by `body`; can exceed `body.len()`.
|
/// Backing allocation retained by `body`; can exceed `body.len()`.
|
||||||
body_allocated: usize,
|
body_allocated: usize,
|
||||||
@@ -181,6 +181,9 @@ fn hot_entry_cost(
|
|||||||
.sum::<usize>();
|
.sum::<usize>();
|
||||||
body_allocated
|
body_allocated
|
||||||
.saturating_add(std::mem::size_of::<Entry>())
|
.saturating_add(std::mem::size_of::<Entry>())
|
||||||
|
// Arc<HeaderMap> owns the actual map on a separate allocation.
|
||||||
|
.saturating_add(std::mem::size_of::<HeaderMap>())
|
||||||
|
.saturating_add(2 * std::mem::size_of::<usize>())
|
||||||
.saturating_add(index_heap)
|
.saturating_add(index_heap)
|
||||||
.saturating_add(header_heap)
|
.saturating_add(header_heap)
|
||||||
.saturating_add(string_vec_heap(vary))
|
.saturating_add(string_vec_heap(vary))
|
||||||
@@ -333,8 +336,8 @@ struct Store {
|
|||||||
control_revision: u64,
|
control_revision: u64,
|
||||||
scope_generations: HashMap<String, u64>,
|
scope_generations: HashMap<String, u64>,
|
||||||
key_generations: HashMap<Key, u64>,
|
key_generations: HashMap<Key, u64>,
|
||||||
domains: BTreeMap<(String, String), DomainCounters>,
|
domains: BTreeMap<String, BTreeMap<String, DomainCounters>>,
|
||||||
last_sweep: Option<Instant>,
|
domain_count: usize,
|
||||||
}
|
}
|
||||||
impl Store {
|
impl Store {
|
||||||
fn index_variant(&mut self, base_key: Key, key: Key) {
|
fn index_variant(&mut self, base_key: Key, key: Key) {
|
||||||
@@ -360,39 +363,24 @@ impl Store {
|
|||||||
Some(entry)
|
Some(entry)
|
||||||
}
|
}
|
||||||
fn domain(&mut self, scope: &str, domain: &str) -> Option<&mut DomainCounters> {
|
fn domain(&mut self, scope: &str, domain: &str) -> Option<&mut DomainCounters> {
|
||||||
let key = (scope.to_owned(), domain.to_owned());
|
// The common path is a borrowed lookup: no allocation of scope/domain
|
||||||
// Cardinality is bounded independently of resident cache capacity.
|
// strings for every cache hit or log-reason counter update.
|
||||||
if self.domains.len() >= 4096 && !self.domains.contains_key(&key) {
|
if self.domains.get(scope).is_some_and(|d| d.contains_key(domain)) {
|
||||||
|
return self.domains.get_mut(scope)?.get_mut(domain);
|
||||||
|
}
|
||||||
|
if self.domain_count >= 4096 {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
Some(self.domains.entry(key).or_default())
|
self.domain_count += 1;
|
||||||
|
Some(self.domains.entry(scope.to_owned()).or_default()
|
||||||
|
.entry(domain.to_owned()).or_default())
|
||||||
}
|
}
|
||||||
fn sweep(&mut self) -> usize {
|
fn saved_body_hit(&mut self, scope: &str, domain: &str, bytes: usize) {
|
||||||
if self
|
// Every admitted HOT insertion registered its domain. If the bounded
|
||||||
.last_sweep
|
// stats table is full, skip accounting for an unregistered domain.
|
||||||
.is_some_and(|v| v.elapsed() < Duration::from_secs(1))
|
if let Some(c) = self.domains.get_mut(scope).and_then(|d| d.get_mut(domain)) {
|
||||||
{
|
c.saved_body_bytes = c.saved_body_bytes.saturating_add(bytes as u64);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
self.last_sweep = Some(Instant::now());
|
|
||||||
let stale: Vec<_> = self
|
|
||||||
.entries
|
|
||||||
.iter()
|
|
||||||
.filter(|(_, e)| {
|
|
||||||
let age = e.initial_age.saturating_add(e.received.elapsed()).as_secs();
|
|
||||||
age >= retention_deadline(
|
|
||||||
e.ttl,
|
|
||||||
e.stale_while_revalidate,
|
|
||||||
e.stale_if_error,
|
|
||||||
e.origin_etag.is_some() || e.origin_last_modified.is_some(),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.map(|(k, _)| *k)
|
|
||||||
.collect();
|
|
||||||
for key in &stale {
|
|
||||||
self.remove(key);
|
|
||||||
}
|
|
||||||
stale.len()
|
|
||||||
}
|
}
|
||||||
fn next_sequence(&mut self) -> u64 {
|
fn next_sequence(&mut self) -> u64 {
|
||||||
// No practical wrapping, but a wrap must not corrupt LRU bookkeeping.
|
// No practical wrapping, but a wrap must not corrupt LRU bookkeeping.
|
||||||
|
|||||||
Vendored
+4
@@ -73,6 +73,7 @@ pub struct Cache {
|
|||||||
fill_flight_sequence: AtomicU64,
|
fill_flight_sequence: AtomicU64,
|
||||||
collapse_waiters: AtomicU64,
|
collapse_waiters: AtomicU64,
|
||||||
bans: Mutex<Vec<BanRule>>,
|
bans: Mutex<Vec<BanRule>>,
|
||||||
|
ban_rule_count: AtomicU64,
|
||||||
ban_sequence: AtomicU64,
|
ban_sequence: AtomicU64,
|
||||||
proactive_scheduled_keys: Mutex<HashSet<Key>>,
|
proactive_scheduled_keys: Mutex<HashSet<Key>>,
|
||||||
proactive_inflight: AtomicU64,
|
proactive_inflight: AtomicU64,
|
||||||
@@ -347,6 +348,9 @@ fn hot_resident_age(entry: &Entry) -> Duration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn matching_hot_key(store: &Store, ticket: &Ticket) -> Option<Key> {
|
fn matching_hot_key(store: &Store, ticket: &Ticket) -> Option<Key> {
|
||||||
|
if store.entries.get(&ticket.key).is_some_and(|entry| entry.vary.is_empty()) {
|
||||||
|
return Some(ticket.key);
|
||||||
|
}
|
||||||
store
|
store
|
||||||
.variants
|
.variants
|
||||||
.get(&ticket.key)?
|
.get(&ticket.key)?
|
||||||
|
|||||||
Vendored
+3
@@ -19,3 +19,6 @@ include!("tests/cold_tier_tests.rs");
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
include!("tests/http_invalidation_tests.rs");
|
include!("tests/http_invalidation_tests.rs");
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
include!("tests/hot_hit_034_tests.rs");
|
||||||
Vendored
-1
@@ -84,7 +84,6 @@ mod dashboard_tests {
|
|||||||
for entry in store.entries.values_mut() {
|
for entry in store.entries.values_mut() {
|
||||||
entry.received = Instant::now() - Duration::from_secs(2 * 60 * 60);
|
entry.received = Instant::now() - Duration::from_secs(2 * 60 * 60);
|
||||||
}
|
}
|
||||||
store.last_sweep = None;
|
|
||||||
}
|
}
|
||||||
let dashboard = cache.dashboard(None, 0, 50);
|
let dashboard = cache.dashboard(None, 0, 50);
|
||||||
assert_eq!(dashboard.matching_objects, 1);
|
assert_eq!(dashboard.matching_objects, 1);
|
||||||
|
|||||||
Vendored
+172
@@ -0,0 +1,172 @@
|
|||||||
|
mod hot_hit_034_tests {
|
||||||
|
use super::*;
|
||||||
|
use http_body_util::BodyExt;
|
||||||
|
|
||||||
|
fn settings() -> Settings {
|
||||||
|
Settings { enabled: true, ..Settings::default() }
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn publish(
|
||||||
|
cache: &Arc<Cache>,
|
||||||
|
settings: &Settings,
|
||||||
|
path: &str,
|
||||||
|
body: &'static str,
|
||||||
|
transformed: bool,
|
||||||
|
) -> Ticket {
|
||||||
|
let ticket = cache.ticket_scoped(
|
||||||
|
34, "app", "http", "cache.example", "origin@127.0.0.1:8080",
|
||||||
|
path, &HeaderMap::new(),
|
||||||
|
).expect("cache ticket");
|
||||||
|
let mut response = Response::new(Body::from(body));
|
||||||
|
response.headers_mut().insert(
|
||||||
|
"cache-control", HeaderValue::from_static("public, max-age=31536000"),
|
||||||
|
);
|
||||||
|
response.headers_mut().insert(
|
||||||
|
"etag", HeaderValue::from_static("\"cached-representation\""),
|
||||||
|
);
|
||||||
|
if transformed {
|
||||||
|
response.extensions_mut().insert(crate::transform::Applied {
|
||||||
|
kind: crate::transform::Kind::Css,
|
||||||
|
original_bytes: body.len(),
|
||||||
|
transformed_bytes: body.len(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
let policy = plan(StatusCode::OK, response.headers(), settings, Duration::ZERO)
|
||||||
|
.expect("public static object cacheable");
|
||||||
|
cache.wrap(response, ticket.clone(), policy, settings)
|
||||||
|
.into_body().collect().await.unwrap();
|
||||||
|
ticket
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn hot_hit_headers_are_independent_and_lru_counters_remain_exact() {
|
||||||
|
let cache = Cache::new(34);
|
||||||
|
let settings = settings();
|
||||||
|
let ticket = publish(&cache, &settings, "/theme.css", "body{color:red}", true).await;
|
||||||
|
let initial = cache.view();
|
||||||
|
let before = cache.dashboard(Some("app"), 0, 10);
|
||||||
|
assert_eq!(before.matching_objects, 1);
|
||||||
|
assert!(before.objects[0].transformed);
|
||||||
|
|
||||||
|
for i in 1..=500 {
|
||||||
|
let hit = cache.get(&ticket).expect("HOT cache hit");
|
||||||
|
assert_eq!(hit.hits, i);
|
||||||
|
assert!(hit.transformed);
|
||||||
|
assert!(hit.response.extensions().get::<crate::transform::CachedTransformed>().is_some());
|
||||||
|
assert_eq!(hit.response.headers()["etag"], "\"cached-representation\"");
|
||||||
|
let mut independent = hit.response;
|
||||||
|
independent.headers_mut().insert("etag", HeaderValue::from_static("\"client-only\""));
|
||||||
|
if i == 500 {
|
||||||
|
assert_eq!(independent.into_body().collect().await.unwrap().to_bytes(), Bytes::from_static(b"body{color:red}"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let after = cache.view();
|
||||||
|
assert_eq!(after.entries, 1);
|
||||||
|
assert_eq!(after.hot_allocated_bytes, initial.hot_allocated_bytes);
|
||||||
|
assert_eq!(after.hot_logical_bytes, initial.hot_logical_bytes);
|
||||||
|
assert_eq!(after.hits.saturating_sub(initial.hits), 500);
|
||||||
|
let store = cache.store.lock().unwrap();
|
||||||
|
assert_eq!(store.entries.len(), 1);
|
||||||
|
assert_eq!(store.lru.len(), 1);
|
||||||
|
assert_eq!(store.variants.len(), 1);
|
||||||
|
drop(store);
|
||||||
|
let dashboard = cache.dashboard(Some("app"), 0, 10);
|
||||||
|
assert_eq!(dashboard.objects[0].hits, 500);
|
||||||
|
assert_eq!(dashboard.domains[0].counters.saved_body_bytes, 500 * 15);
|
||||||
|
assert_eq!(cache.get(&ticket).unwrap().response.headers()["etag"], "\"cached-representation\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn concurrent_hot_hits_have_unique_monotonic_counts_and_bounded_indexes() {
|
||||||
|
let cache = Cache::new(34);
|
||||||
|
let ticket = publish(&cache, &settings(), "/shared.css", "cachebody", false).await;
|
||||||
|
let workers = 6;
|
||||||
|
let per_worker = 300;
|
||||||
|
let mut threads = Vec::new();
|
||||||
|
for _ in 0..workers {
|
||||||
|
let cache = Arc::clone(&cache);
|
||||||
|
let ticket = ticket.clone();
|
||||||
|
threads.push(std::thread::spawn(move || {
|
||||||
|
let mut hits = Vec::with_capacity(per_worker);
|
||||||
|
for _ in 0..per_worker {
|
||||||
|
let hit = cache.get(&ticket).expect("concurrent HOT hit");
|
||||||
|
assert_eq!(hit.response.headers()["etag"], "\"cached-representation\"");
|
||||||
|
hits.push(hit.hits);
|
||||||
|
}
|
||||||
|
hits
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
let mut counts: Vec<_> = threads.into_iter().flat_map(|t| t.join().unwrap()).collect();
|
||||||
|
counts.sort_unstable();
|
||||||
|
assert_eq!(counts, (1..=(workers * per_worker) as u64).collect::<Vec<_>>());
|
||||||
|
assert_eq!(cache.view().hits, (workers * per_worker) as u64);
|
||||||
|
let store = cache.store.lock().unwrap();
|
||||||
|
assert_eq!(store.lru.len(), 1);
|
||||||
|
assert_eq!(store.entries.len(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn hot_lru_eviction_and_ban_are_preserved() {
|
||||||
|
let cache = Cache::new(34);
|
||||||
|
let settings = Settings { max_entries: 2, ..settings() };
|
||||||
|
let a = publish(&cache, &settings, "/a.css", "AAAA", false).await;
|
||||||
|
let b = publish(&cache, &settings, "/b.css", "BBBB", false).await;
|
||||||
|
assert!(cache.get(&a).is_some(), "A becomes most recently used");
|
||||||
|
let c = publish(&cache, &settings, "/c.css", "CCCC", false).await;
|
||||||
|
assert!(cache.get(&a).is_some());
|
||||||
|
assert!(cache.get(&b).is_none(), "B is least recently used");
|
||||||
|
assert!(cache.get(&c).is_some());
|
||||||
|
|
||||||
|
let ban = cache.invalidate(InvalidationRequest {
|
||||||
|
operation: InvalidationOperation::Ban,
|
||||||
|
selector: InvalidationSelector::Exact,
|
||||||
|
value: "/a.css".into(),
|
||||||
|
host: Some("cache.example".into()),
|
||||||
|
vhost: Some("app".into()),
|
||||||
|
ttl_seconds: Some(3600),
|
||||||
|
confirm_wide: false,
|
||||||
|
}).unwrap();
|
||||||
|
assert_eq!(cache.ban_rule_count.load(Ordering::Acquire), 1);
|
||||||
|
assert!(cache.get(&a).is_none(), "BAN must block cached A");
|
||||||
|
assert!(cache.remove_ban(ban.ban_id.unwrap()));
|
||||||
|
assert_eq!(cache.ban_rule_count.load(Ordering::Acquire), 0);
|
||||||
|
assert!(cache.get(&c).is_some(), "unrelated C must remain cached");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
#[ignore = "manual in-process timing only; NOT HTTP RPS"]
|
||||||
|
async fn manual_hot_lookup_microbenchmark() {
|
||||||
|
let cache = Cache::new(34);
|
||||||
|
let ticket = publish(&cache, &settings(), "/bench.css", "smallbody", true).await;
|
||||||
|
for _ in 0..1_000 {
|
||||||
|
std::hint::black_box(cache.get(&ticket).unwrap());
|
||||||
|
}
|
||||||
|
let iterations = 100_000;
|
||||||
|
let start = Instant::now();
|
||||||
|
for _ in 0..iterations {
|
||||||
|
std::hint::black_box(cache.get(&ticket).unwrap());
|
||||||
|
}
|
||||||
|
let duration = start.elapsed();
|
||||||
|
eprintln!("HOT lookup incl. response materialization: {:.1} ns/op ({} hits); NOT network RPS",
|
||||||
|
duration.as_secs_f64() * 1e9 / iterations as f64, iterations);
|
||||||
|
assert_eq!(cache.view().hits, iterations + 1_000);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn stale_object_remains_available_for_explicit_max_stale() {
|
||||||
|
let cache = Cache::new(34);
|
||||||
|
let ticket = publish(&cache, &settings(), "/old.css", "oldbody", false).await;
|
||||||
|
{
|
||||||
|
let mut store = cache.store.lock().unwrap();
|
||||||
|
store.entries.values_mut().next().unwrap().received =
|
||||||
|
Instant::now() - Duration::from_secs(700_000);
|
||||||
|
}
|
||||||
|
assert!(cache.get(&ticket).is_none(), "expired freshness is not an unconditional HIT");
|
||||||
|
assert_eq!(cache.view().entries, 1, "stale representation must survive for revalidation");
|
||||||
|
let mut stale_ticket = ticket;
|
||||||
|
stale_ticket.request_headers.insert(
|
||||||
|
"cache-control", HeaderValue::from_static("max-stale"),
|
||||||
|
);
|
||||||
|
assert!(cache.get(&stale_ticket).unwrap().stale);
|
||||||
|
}
|
||||||
|
}
|
||||||
Vendored
+1
-5
@@ -109,10 +109,6 @@ impl Cache {
|
|||||||
}
|
}
|
||||||
pub fn revalidation(&self, ticket: &Ticket) -> Option<Revalidation> {
|
pub fn revalidation(&self, ticket: &Ticket) -> Option<Revalidation> {
|
||||||
let mut store = self.store.lock().unwrap_or_else(|e| e.into_inner());
|
let mut store = self.store.lock().unwrap_or_else(|e| e.into_inner());
|
||||||
let expired = store.sweep();
|
|
||||||
self.counters
|
|
||||||
.expired
|
|
||||||
.fetch_add(expired as u64, Ordering::Relaxed);
|
|
||||||
if store.revision != ticket.revision
|
if store.revision != ticket.revision
|
||||||
|| store.generation != ticket.generation
|
|| store.generation != ticket.generation
|
||||||
|| store
|
|| store
|
||||||
@@ -142,7 +138,7 @@ impl Cache {
|
|||||||
.saturating_add(entry.received.elapsed())
|
.saturating_add(entry.received.elapsed())
|
||||||
.as_secs();
|
.as_secs();
|
||||||
Some(Revalidation {
|
Some(Revalidation {
|
||||||
headers: entry.headers.clone(),
|
headers: entry.headers.as_ref().clone(),
|
||||||
body: entry.body.clone(),
|
body: entry.body.clone(),
|
||||||
body_allocated: entry.body_allocated,
|
body_allocated: entry.body_allocated,
|
||||||
_transient_leases: Vec::new(),
|
_transient_leases: Vec::new(),
|
||||||
|
|||||||
@@ -94,11 +94,14 @@ pub(crate) fn compile_backend_with_timeout(
|
|||||||
connect_timeout,
|
connect_timeout,
|
||||||
)?
|
)?
|
||||||
};
|
};
|
||||||
|
let request_origin = format!("{}://{request_authority}", url.scheme());
|
||||||
|
let request_origin_uri: http::Uri = request_origin.parse()?;
|
||||||
Ok(CompiledBackend {
|
Ok(CompiledBackend {
|
||||||
address_policy,
|
address_policy,
|
||||||
id: backend.id.clone(),
|
id: backend.id.clone(),
|
||||||
origin: format!("{}://{authority}", url.scheme()),
|
origin: format!("{}://{authority}", url.scheme()),
|
||||||
request_origin: format!("{}://{request_authority}", url.scheme()),
|
request_origin,
|
||||||
|
request_origin_uri,
|
||||||
host_header: authority.parse()?,
|
host_header: authority.parse()?,
|
||||||
preserve_host: backend.preserve_host,
|
preserve_host: backend.preserve_host,
|
||||||
protocol: backend.protocol,
|
protocol: backend.protocol,
|
||||||
|
|||||||
@@ -174,6 +174,8 @@ pub struct CompiledBackend {
|
|||||||
pub origin: String,
|
pub origin: String,
|
||||||
/// HTTP request origin. For HTTPS this may carry a separate verified TLS name.
|
/// HTTP request origin. For HTTPS this may carry a separate verified TLS name.
|
||||||
pub request_origin: String,
|
pub request_origin: String,
|
||||||
|
/// Parsed once at configuration publish; reused for every upstream request.
|
||||||
|
pub request_origin_uri: http::Uri,
|
||||||
pub host_header: HeaderValue,
|
pub host_header: HeaderValue,
|
||||||
pub preserve_host: bool,
|
pub preserve_host: bool,
|
||||||
pub protocol: UpstreamProtocol,
|
pub protocol: UpstreamProtocol,
|
||||||
|
|||||||
+21
-7
@@ -136,8 +136,17 @@ impl Logs {
|
|||||||
self.settings.load().capture_country
|
self.settings.load().capture_country
|
||||||
}
|
}
|
||||||
pub fn push(&self, entry: LogEntry) {
|
pub fn push(&self, entry: LogEntry) {
|
||||||
// String cloning and eviction cleanup do not need the history mutex.
|
let has_viewers = self.live.receiver_count() != 0;
|
||||||
let history_entry = entry.clone();
|
let has_sink = self.settings.load().enabled();
|
||||||
|
// The usual history-only configuration needs no deep copy at all.
|
||||||
|
// When external consumers are present, clone exactly for history and
|
||||||
|
// keep the original entry available for streaming/sink delivery.
|
||||||
|
let mut external = Some(entry);
|
||||||
|
let history_entry = if has_viewers || has_sink {
|
||||||
|
external.as_ref().expect("entry").clone()
|
||||||
|
} else {
|
||||||
|
external.take().expect("entry")
|
||||||
|
};
|
||||||
let evicted = if let Ok(mut entries) = self.entries.try_lock() {
|
let evicted = if let Ok(mut entries) = self.entries.try_lock() {
|
||||||
let evicted = if entries.len() == HISTORY_CAPACITY {
|
let evicted = if entries.len() == HISTORY_CAPACITY {
|
||||||
entries.pop_front()
|
entries.pop_front()
|
||||||
@@ -150,13 +159,18 @@ impl Logs {
|
|||||||
self.dropped.fetch_add(1, Ordering::Relaxed);
|
self.dropped.fetch_add(1, Ordering::Relaxed);
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
// Destroy evicted strings outside of the history lock.
|
||||||
drop(evicted);
|
drop(evicted);
|
||||||
// No live viewers means no reason to allocate/clone a second LogEntry.
|
if let Some(entry) = external {
|
||||||
// History retention and external sinks remain unchanged.
|
if has_viewers {
|
||||||
if self.live.receiver_count() != 0 {
|
let _ = self.live.send(entry.clone());
|
||||||
let _ = self.live.send(entry.clone());
|
}
|
||||||
|
// Snapshot the sink choice once. This preserves sink drop
|
||||||
|
// accounting and avoids a second ArcSwap load per request.
|
||||||
|
if has_sink && self.sink.try_send(entry).is_err() {
|
||||||
|
self.sink_dropped.fetch_add(1, Ordering::Relaxed);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
self.push_sink(entry);
|
|
||||||
}
|
}
|
||||||
fn push_sink(&self, entry: LogEntry) {
|
fn push_sink(&self, entry: LogEntry) {
|
||||||
if self.settings.load().enabled() && self.sink.try_send(entry).is_err() {
|
if self.settings.load().enabled() && self.sink.try_send(entry).is_err() {
|
||||||
|
|||||||
@@ -422,4 +422,40 @@ mod tests {
|
|||||||
assert_eq!(stats.sent, 1);
|
assert_eq!(stats.sent, 1);
|
||||||
assert_eq!(stats.errors, 0);
|
assert_eq!(stats.errors, 0);
|
||||||
}
|
}
|
||||||
|
#[test]
|
||||||
|
fn history_only_mode_preserves_exact_fields_without_any_live_or_sink_copies() {
|
||||||
|
let logs = Logs::default();
|
||||||
|
let item = entry();
|
||||||
|
let expected = serde_json::to_value(&item).unwrap();
|
||||||
|
logs.push(item);
|
||||||
|
let saved = logs.recent();
|
||||||
|
assert_eq!(saved.len(), 1);
|
||||||
|
assert_eq!(serde_json::to_value(&saved[0]).unwrap(), expected);
|
||||||
|
assert_eq!(logs.stats().queue_dropped, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn live_viewers_receive_same_event_as_persisted_history() {
|
||||||
|
let logs = Logs::default();
|
||||||
|
let mut live = logs.subscribe();
|
||||||
|
let item = entry();
|
||||||
|
let expected = serde_json::to_value(&item).unwrap();
|
||||||
|
logs.push(item);
|
||||||
|
assert_eq!(serde_json::to_value(live.try_recv().unwrap()).unwrap(), expected);
|
||||||
|
assert_eq!(serde_json::to_value(&logs.recent()[0]).unwrap(), expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn enabled_external_sink_retains_existing_queue_drop_accounting() {
|
||||||
|
// The default test Logs has a closed sink receiver. Delivering to a
|
||||||
|
// configured external sink must still account for its failure.
|
||||||
|
let logs = Logs::default();
|
||||||
|
let mut settings = Settings::default();
|
||||||
|
settings.file.enabled = true;
|
||||||
|
logs.configure(settings);
|
||||||
|
logs.push(entry());
|
||||||
|
assert_eq!(logs.recent().len(), 1);
|
||||||
|
assert_eq!(logs.stats().queue_dropped, 1);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
+14
-1
@@ -301,6 +301,7 @@ pub struct MeteredBody {
|
|||||||
/// For a response, backend selection is final before this wrapper is made.
|
/// For a response, backend selection is final before this wrapper is made.
|
||||||
/// Keep the selected lease alive and avoid locking Exchange.backend per frame.
|
/// Keep the selected lease alive and avoid locking Exchange.backend per frame.
|
||||||
response_backend: Option<Arc<crate::balance::Lease>>,
|
response_backend: Option<Arc<crate::balance::Lease>>,
|
||||||
|
request_backend: Option<Arc<crate::balance::Lease>>,
|
||||||
direction: Direction,
|
direction: Direction,
|
||||||
timer: Option<Pin<Box<Sleep>>>,
|
timer: Option<Pin<Box<Sleep>>>,
|
||||||
deadline: tokio::time::Instant,
|
deadline: tokio::time::Instant,
|
||||||
@@ -317,6 +318,7 @@ impl MeteredBody {
|
|||||||
inner,
|
inner,
|
||||||
exchange: Some(exchange),
|
exchange: Some(exchange),
|
||||||
response_backend,
|
response_backend,
|
||||||
|
request_backend: None,
|
||||||
direction,
|
direction,
|
||||||
// Ready/empty bodies never need a timer allocation. Keep the
|
// Ready/empty bodies never need a timer allocation. Keep the
|
||||||
// original deadline so a delayed first poll still times out.
|
// original deadline so a delayed first poll still times out.
|
||||||
@@ -330,6 +332,7 @@ impl MeteredBody {
|
|||||||
self.finished = true;
|
self.finished = true;
|
||||||
self.timer.take();
|
self.timer.take();
|
||||||
self.response_backend.take();
|
self.response_backend.take();
|
||||||
|
self.request_backend.take();
|
||||||
self.exchange.take();
|
self.exchange.take();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -350,7 +353,17 @@ impl HttpBody for MeteredBody {
|
|||||||
if let (Some(data), Some(exchange)) = (frame.data_ref(), this.exchange.as_ref()) {
|
if let (Some(data), Some(exchange)) = (frame.data_ref(), this.exchange.as_ref()) {
|
||||||
let count = data.len() as u64;
|
let count = data.len() as u64;
|
||||||
match this.direction {
|
match this.direction {
|
||||||
Direction::Request => exchange.backend_bytes(count, true),
|
Direction::Request => {
|
||||||
|
// Backend is selected before a non-empty upstream
|
||||||
|
// upload is polled. No retry of a streamed write.
|
||||||
|
if this.request_backend.is_none() {
|
||||||
|
this.request_backend = exchange.backend
|
||||||
|
.lock().unwrap_or_else(|e| e.into_inner()).clone();
|
||||||
|
}
|
||||||
|
if let Some(lease) = &this.request_backend {
|
||||||
|
lease.bytes(count, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
Direction::Response => {
|
Direction::Response => {
|
||||||
if let Some(lease) = &this.response_backend {
|
if let Some(lease) = &this.response_backend {
|
||||||
lease.bytes(count, false);
|
lease.bytes(count, false);
|
||||||
|
|||||||
@@ -125,7 +125,9 @@ let cache_settings = route
|
|||||||
let transform_settings = route.frontend.as_ref().map(|f| &f.transform);
|
let transform_settings = route.frontend.as_ref().map(|f| &f.transform);
|
||||||
let scope = route.frontend.as_ref().map(|f| f.id.as_str()).unwrap_or("");
|
let scope = route.frontend.as_ref().map(|f| f.id.as_str()).unwrap_or("");
|
||||||
if let Some(exchange) = request.extensions().get::<Arc<Exchange>>() {
|
if let Some(exchange) = request.extensions().get::<Arc<Exchange>>() {
|
||||||
*exchange.route.lock().unwrap_or_else(|e| e.into_inner()) = Some(route.id.clone());
|
// The resolved route was already recorded before local response, LB and
|
||||||
|
// ACL decisions. Do not acquire the route mutex and copy its ID twice on
|
||||||
|
// every reverse-proxy request.
|
||||||
exchange.set_cache_enabled(cache_settings.active_for(route.cache));
|
exchange.set_cache_enabled(cache_settings.active_for(route.cache));
|
||||||
exchange.set_transform_enabled(transform_settings.is_some_and(|settings| settings.enabled));
|
exchange.set_transform_enabled(transform_settings.is_some_and(|settings| settings.enabled));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
fn request_id_hash(sequence: u64) -> String {
|
fn request_id_hash(sequence: u64) -> String {
|
||||||
use rand::TryRng;
|
|
||||||
use sha2::{Digest, Sha256};
|
use sha2::{Digest, Sha256};
|
||||||
|
|
||||||
let mut nonce = [0u8; 32];
|
// Thread-local CSPRNG is seeded (and periodically reseeded) from the OS.
|
||||||
let mut rng = rand::rngs::SysRng;
|
// Do not make a getrandom syscall on the hot path for every HTTP request.
|
||||||
rng.try_fill_bytes(&mut nonce)
|
// Keep hashing the per-process sequence as before for the same ID format.
|
||||||
.expect("secure operating system random source unavailable");
|
let nonce: [u8; 32] = rand::random();
|
||||||
let mut hash = Sha256::new();
|
let mut hash = Sha256::new();
|
||||||
hash.update(sequence.to_be_bytes());
|
hash.update(sequence.to_be_bytes());
|
||||||
hash.update(nonce);
|
hash.update(nonce);
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ mod request_id_tests {
|
|||||||
.all(|b| b.is_ascii_digit() || (b'a'..=b'f').contains(&b)));
|
.all(|b| b.is_ascii_digit() || (b'a'..=b'f').contains(&b)));
|
||||||
assert!(
|
assert!(
|
||||||
seen.insert(id),
|
seen.insert(id),
|
||||||
"fixed sequence must still use independent OS entropy"
|
"fixed sequence must still use independent CSPRNG output"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -595,4 +595,23 @@ mod graceful_h2_tests {
|
|||||||
assert!(!is_graceful_h2_goaway(&protocol));
|
assert!(!is_graceful_h2_goaway(&protocol));
|
||||||
assert!(!is_graceful_h2_goaway(&local));
|
assert!(!is_graceful_h2_goaway(&local));
|
||||||
}
|
}
|
||||||
|
#[test]
|
||||||
|
fn compiled_request_origin_matches_previous_uri_parser() {
|
||||||
|
let mut config = crate::config::demo_config("127.0.0.1:9000".parse().unwrap());
|
||||||
|
config.vhosts[0].backends[0].url = "https://127.0.0.1:9000".into();
|
||||||
|
config.vhosts[0].backends[0].tls_server_name = Some("backend.example".into());
|
||||||
|
let snapshot = crate::config::compile(config, 1, &validation_policy()).unwrap();
|
||||||
|
let backend = &snapshot.pools[0].members[0].backend;
|
||||||
|
assert_eq!(backend.request_origin_uri.to_string(), backend.request_origin);
|
||||||
|
for suffix in [
|
||||||
|
"/", "/static/main.css", "/path?x=1&y=2", "/p%2Fq?url=https%3A//example.org/a",
|
||||||
|
"/?q=%C5%82&empty=", "/double//slash", "/item#frag",
|
||||||
|
] {
|
||||||
|
let previous = format!("{}{suffix}", backend.request_origin).parse::<Uri>().ok();
|
||||||
|
assert_eq!(upstream_uri(backend, suffix), previous, "{suffix}");
|
||||||
|
}
|
||||||
|
assert!(upstream_uri(backend, "http://attacker.invalid/").is_none());
|
||||||
|
assert_eq!(backend.origin, "https://127.0.0.1:9000");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
+7
-1
@@ -152,7 +152,13 @@ fn retry_safe_method(method: &Method) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn upstream_uri(backend: &crate::config::CompiledBackend, suffix: &str) -> Option<Uri> {
|
fn upstream_uri(backend: &crate::config::CompiledBackend, suffix: &str) -> Option<Uri> {
|
||||||
format!("{}{suffix}", backend.request_origin).parse().ok()
|
// Reuse the validated scheme and authority from the immutable compiled
|
||||||
|
// backend. Only the untrusted path/query is parsed per request. This also
|
||||||
|
// prevents accidental authority changes from rewritten paths.
|
||||||
|
let path: http::uri::PathAndQuery = suffix.parse().ok()?;
|
||||||
|
let mut parts = backend.request_origin_uri.clone().into_parts();
|
||||||
|
parts.path_and_query = Some(path);
|
||||||
|
Uri::from_parts(parts).ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn legacy_websocket_origin(
|
fn legacy_websocket_origin(
|
||||||
|
|||||||
@@ -56,14 +56,11 @@ async fn observe(State(state): State<Arc<App>>, mut request: Request, next: Next
|
|||||||
|| (request.version() == Version::HTTP_3
|
|| (request.version() == Version::HTTP_3
|
||||||
&& request.method() == Method::CONNECT
|
&& request.method() == Method::CONNECT
|
||||||
&& websocket::h3_protocol(&request) == Some("websocket"));
|
&& websocket::h3_protocol(&request) == Some("websocket"));
|
||||||
if request.version() == Version::HTTP_11 {
|
match request.version() {
|
||||||
state.metrics.http1_requests.fetch_add(1, Ordering::Relaxed);
|
Version::HTTP_11 => { state.metrics.http1_requests.fetch_add(1, Ordering::Relaxed); }
|
||||||
}
|
Version::HTTP_2 => { state.metrics.http2_requests.fetch_add(1, Ordering::Relaxed); }
|
||||||
if request.version() == Version::HTTP_2 {
|
Version::HTTP_3 => { state.metrics.http3_requests.fetch_add(1, Ordering::Relaxed); }
|
||||||
state.metrics.http2_requests.fetch_add(1, Ordering::Relaxed);
|
_ => {}
|
||||||
}
|
|
||||||
if request.version() == Version::HTTP_3 {
|
|
||||||
state.metrics.http3_requests.fetch_add(1, Ordering::Relaxed);
|
|
||||||
}
|
}
|
||||||
let id = state.metrics.requests.fetch_add(1, Ordering::Relaxed) + 1;
|
let id = state.metrics.requests.fetch_add(1, Ordering::Relaxed) + 1;
|
||||||
let request_id = request_id_hash(id);
|
let request_id = request_id_hash(id);
|
||||||
|
|||||||
@@ -96,5 +96,21 @@ mod tests {
|
|||||||
}
|
}
|
||||||
assert_eq!(client.rotation_stats().rotations, 0);
|
assert_eq!(client.rotation_stats().rotations, 0);
|
||||||
}
|
}
|
||||||
|
#[test]
|
||||||
|
fn request_recycling_still_has_exact_threshold_after_clock_sampling() {
|
||||||
|
let backend = backend("requests-boundary", 18085);
|
||||||
|
let mut keepalive = crate::balance::Keepalive::default();
|
||||||
|
keepalive.pool_recycle_requests = 1_000;
|
||||||
|
keepalive.pool_recycle_seconds = 0;
|
||||||
|
let client = client_with_keepalive(
|
||||||
|
&backend, AddressPolicy::new(&backend).unwrap(), false, &keepalive,
|
||||||
|
).unwrap();
|
||||||
|
for _ in 0..1_000 { client.inner.client_for_request(); }
|
||||||
|
assert_eq!(client.rotation_stats().rotations, 0);
|
||||||
|
client.inner.client_for_request();
|
||||||
|
assert_eq!(client.rotation_stats().rotations, 1);
|
||||||
|
assert_eq!(client.rotation_stats().generation_requests, 1);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Reference in new issue
Block a user