v0.32.7
This commit is contained in:
1 parent
4f36de240c
commit
c41d1e00a2
18 files changed
+228
-336
No files matched your search
@@ -3,6 +3,13 @@
|
||||
> Operator-facing release history. Historical engineering notes are kept in
|
||||
> [`docs/CHANGELOG_TECHNICAL_ARCHIVE.md`](docs/CHANGELOG_TECHNICAL_ARCHIVE.md).
|
||||
|
||||
## 0.32.7 development follow-up (UI density and H2 diagnostics)
|
||||
|
||||
- Remove per-location button size overrides for Overview refresh/arrangement/unlock and Appearance visual editor/show-all; defer to shared Normal/Compact button sizing.
|
||||
- Make normal/compact/ultra Dashboard density distinguish metric values, charts and non-table panels on desktop and mobile without changing saved settings or grid gaps.
|
||||
- Lower only confirmed graceful H2-close terminal diagnostic duplication to TRACE; preserve 502/access-log details and full error handling for uncorrelated `Canceled` failures.
|
||||
- Add static and optional Chromium regression checks; Rust build and live H2 reproduction remain pending.
|
||||
|
||||
## 0.32.7
|
||||
|
||||
- Handle peer-initiated graceful upstream HTTP/2 GOAWAY(NO_ERROR) by retiring a
|
||||
|
||||
@@ -7,6 +7,12 @@ streaming HTTP/TLS/WebSocket forwarding, raw TCP/UDP stream hosts, IP-bound vhos
|
||||
|
||||
**0.31.9 Certificate API management: inspect and edit credential settings without exposing/rotating the current token, or regenerate one existing token with one-time display. Rust/Cargo and live testing required.**
|
||||
|
||||
## 0.32.7 development follow-up: Appearance and H2 diagnostics
|
||||
|
||||
- Overview **Refresh now**, **Arrange Overview**, **Unlock layout**, and Appearance **Visual Overview editor** / **Show all cards** use the common button sizing, including the global **Compact** preset on mobile.
|
||||
- Dashboard density is more distinguishable in metric tile spacing/numbers, chart heights and non-table panel padding/headers. The grid gutters, visibility/order preferences, refresh cadence and proxy routes remain unchanged.
|
||||
- A terminal request failure tied to a recently confirmed `GOAWAY(NO_ERROR)` is only traced at `TRACE` (not `DEBUG`) as a duplicate upstream diagnostic. It still returns 502 and appears in the access diagnostics; unrelated `Canceled -> connection closed` failures remain genuine errors. No blanket suppression by error string.
|
||||
|
||||
## What changed in 0.32.7
|
||||
|
||||
- **H2 upstream recovery:** gracefully drained upstream H2 connections sending
|
||||
|
||||
+7
-1
@@ -1,12 +1,18 @@
|
||||
# RustProxy roadmap
|
||||
|
||||
## 0.32.7 development follow-up: Appearance and H2-close diagnostics
|
||||
|
||||
- [x] Use common button sizing for Overview quick actions and Appearance visual editor/show-all; preserve the normal and compact global button styles.
|
||||
- [x] Strengthen the distinction between Dashboard density levels for tiles, charts and non-table panels without changing grid gutters or preferences.
|
||||
- [x] Lower only correlated graceful H2 close terminal diagnostics to TRACE; keep 502/access details and uncorrelated cancellations as errors.
|
||||
- [x] Verify the UI sizes with a simulated Chromium browser at desktop and phone widths.
|
||||
|
||||
## 0.32.7 - Mobile Overview and upstream protocol visibility (runtime acceptance pending)
|
||||
|
||||
- [x] Share counter-rate pause/resume handling between Cache, Transform,
|
||||
Overview, backend, Stream and Vhost plots. Retain historical points after
|
||||
backgrounding, skip suspended intervals and restart normal samples after
|
||||
one fresh counter baseline, with no new polling.
|
||||
- [ ] Validate actual minimized-tab/BFCache chart behavior in iOS 27 Safari.
|
||||
- [x] Development follow-up: preserve Network diagnostic chart DOM through
|
||||
periodic refresh and fix descendant CSS selector minification.
|
||||
- [x] Feed Process CPU/RSS and per-interface network charts from the cached
|
||||
|
||||
+24
-22
@@ -2,17 +2,17 @@
|
||||
4140a2956264b44f259e6a37fc00ba02097bbe68b09296e04d3d243c1287129b .env.example
|
||||
9e6356475bf587091bab72246ec9e325b498f7e48a6220e9a18baa50d0a385a6 .gitignore
|
||||
c38904ea10c12fea702f54dbbcad75096a4e89148532dea040a346ecc18c3b8c AGENTS.md
|
||||
77a1df6e671051d8bf6640401e162b319083c8e6cf83cf50edbb6ce0893a8ba3 CHANGELOG.md
|
||||
56df1fa7123e95ca19e67ca11933ec34336216a0f46083121051bac7a1719dbc CHANGELOG.md
|
||||
5d8c6feb5585b8880f7d016dec83f2a8f6cdcbaa7eb5ccc840a6064385d22133 Cargo.lock
|
||||
931e433a8f2e2582bdd76180c60c6c40978a3bb29f66bbd5219a45587a052d95 Cargo.toml
|
||||
25c7f3c8162cbf5cc156439774118a81dae9fdc52b611ec7e40c230fc99a772c Dockerfile
|
||||
2425ba362f88a656516d04c40866e1a43f520a64e5a2c4020e4c7732742229fc README.md
|
||||
7e715a1170780ffeeca83447fda739e4be84b96e9c2a51851175b62f79000478 ROADMAP.md
|
||||
d4f497119527aba2681637caef3f4e1dd8615decc1f691d51e8857108e4cb00d README.md
|
||||
186faafa487edc7a23a1200c8ef8641b00ada263fe5bf994eff2aa76aa94984f ROADMAP.md
|
||||
da8311e3db945290666324a2f24bf4521b365272d7ac3f862ded1be993eea646 UPDATE_CHECK.toml
|
||||
f645f218dd062bf6cb54a8ee634290562cad364a4cccf09f16e3c8303582af8c build.rs
|
||||
ea8d091843f86f4c66a5c76b20268b2feb397070851b6e05c5bc7d7a8d9157eb deploy/README.md
|
||||
4834c278430ddf3bf842995735195368f1ac2c3b5c1d749df4f9238caf1e2b25 deploy/rustproxy.service
|
||||
26a607151fd343a59c6f147e70897c4b1bfeab376348f3270eb8a373503d7be5 dev.sh
|
||||
8397a12bd76b6abb251a9599f7b9be92e4e5a9addaa40ef35ef6942c3ba9994a dev.sh
|
||||
5f51efe621f45512a466fa7f2656867c6502a135ca040f4bfeec06a6919b39b6 docker-agent/README.md
|
||||
7fee7d51a7deb67e73e53a0bdff3aa4630aea9bab9b23a0f9b8001b2169892b1 docker-agent/certificate.go
|
||||
5e4f565c3c9de4dba897af2e801ea646a83395e72eae4717a6d502dff2fcec10 docker-agent/docker-agent.env.example
|
||||
@@ -36,7 +36,7 @@ fb99fac0a490af262a0ecdad593ffe5164004c2166fe7ddd607476bcc56a1623 docs/CACHE.md
|
||||
c8e69e492179ce39958cc63615cf46c4ac08cfdb7f3483aaab66868a3abcd687 docs/CONTAINER.md
|
||||
833ddb12f23dcac796223521388b19c6ec3ea04c5550cf1c5f4ea4eb7c58f3a0 docs/CUSTOM_LOCATIONS.md
|
||||
4d70797bda8d227787fcff897951e702e2458fc6c6f5352aa0b5577595bd834b docs/DOCKER_DISCOVERY.md
|
||||
5324b215075214a5bb9b388bc82d6491eacfc507df95856d1aecedd184e25b80 docs/ERROR_LOGGING.md
|
||||
46811a09a03d83f4af686c33e30e3f94d0508afe2c75147a26885c7247c49cbd docs/ERROR_LOGGING.md
|
||||
f749f7bd2eb4ae9c484f77a3cd8cd5ff21445319a3938e0384a3414134fe713a docs/FILE_LOGS.md
|
||||
36599e0b59164e662442f3e8203c16b3123d09b7684d8ecdbffce42d22cc221b docs/HTTP3.md
|
||||
a00ec3c1d3b28ba10677435128e031e5f18fe8c5cef2ac90eb0f6779cefeb434 docs/INSTALL.md
|
||||
@@ -61,9 +61,9 @@ d85c5567fc6a7714b96ad7cfe4ee9ff2085f84c4f31534a6484340d03a73e0f7 docs/RENEWAL.m
|
||||
ec7e32fd19e6ba6ed1732f1f3dd92ac0860609e8c0bbd3c1998840cdfb24bf54 docs/SECURITY.md
|
||||
620b69e566d27af04f0604f4ca3f88cf95cdfea7fbc6ae9dd92446d2b2b5d9be docs/SECURITY_AUDIT.md
|
||||
007537ee971463072b2482dfa4fdcf1955f837ced0b711d4eef3b6267d16d4f6 docs/SECURITY_AUDIT_0.31.0.md
|
||||
a41cef4a4da5e098fe3e9dfa0fffb3625f2e09792eacdf5dbf8d8fd532146d26 docs/SETTINGS.md
|
||||
3ab9fa2a537c00c13f294a09d0109e6a1c2e10f105902b84104bb9b613e61993 docs/SETTINGS.md
|
||||
8fc112cb45a2f35ef5b0dd4371aa6f43aca4df85db62c6ae02e56d74a3b702ae docs/STREAMS.md
|
||||
d420880a9a4b3d2fcd0458384aca7fd022afb6fca9abfa2b7ac2a5f32f916822 docs/TEST_REPORT.md
|
||||
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 docs/TEST_REPORT.md
|
||||
cfb452d8496839e832b5fbacdd4e52525b0ecc3112fbb62340c1e580bd5c1717 docs/TODO.md
|
||||
751c9b13b47d0959a8575d6e82bdecba988b950a374ba0b084fbba08b4b65ebe docs/TRANSFORM.md
|
||||
fe3ec6ca16ff933239c12dacf39dd7b45717c0551a8b9f6ce601bf78136c9e37 docs/TRANSPORT.md
|
||||
@@ -223,7 +223,7 @@ c2e5f554810b8e34fb47361fb90a01073a2e332ee26d82e030956fad3ec1f83e src/admin/web/
|
||||
c28f4254ddc1f720d62646ee0f0b590b60a89c0bf447e8ec74ff3dde0c7635ba src/admin/web/settings.js
|
||||
8eadbada619b15087783dcfa0e889a81f88e78034d084c5ab616f7912b835940 src/admin/web/status_200.html
|
||||
c13cffe18a616fe5faa5ee945ab0d94d8d392ae8f32474c62fe41010e063ddb1 src/admin/web/streams.js
|
||||
cd89785fc8f27353983846c799f9256a1a893d775cb4853fb62b76c29e42f8c7 src/admin/web/style.css
|
||||
57081d31d7a7b7842e45725848fa4a4e6595e0cf769c7969797202ca99be439f src/admin/web/style.css
|
||||
d290c048450655b3eeae7c6ec54a82d645d1965513694ab29fdf7eef796a1abd src/admin/web/traffic-panel.js
|
||||
69f412bd897e45f4889b71e9982cfff56df9ef20ba2da109b454713a5ecd7c74 src/admin/web/transform-panel.js
|
||||
d816f2f70eef398c18091479320c36d07f9afe07278a250b840ebcdd7bc715f2 src/admin/web/vhosts/core.js
|
||||
@@ -246,13 +246,13 @@ c96a87e82ff0c1c9ce3d0cd5135903bb53af78d1c4fb6ebfe5fea503bf5644ea src/auth/store
|
||||
a00571b409d305af86ab2a57a25434b5ab58706772df440d017fc1fec097f7b4 src/backup/tests.rs
|
||||
f5afae218f3a6f91bc2f1f5a90094630ce5b7ca574de61807b5a317b13937ec2 src/backup/validation.rs
|
||||
426a946b2c9e244f09f6cbc5f9664b8ad0737529a9bb5a3d549d27196a1f8043 src/balance.rs
|
||||
f4014258dfa2b0e5c05daa220203d7536f0ae58343d82e0be7613f138edf75af src/balance/health.rs
|
||||
7a59ded466173e67ee8967bdf50d667b66a9db33a6770c03aeee58d7c482c0c1 src/balance/lease_runtime.rs
|
||||
94dca2b1e497bddbe6de5d272800a40f59447ef824dc894e3c410e751a4315ea src/balance/health.rs
|
||||
59d90e709bfc2be6cd48576f1c1d222891523853a46f2561f0562d74d01f60a5 src/balance/lease_runtime.rs
|
||||
aed9ed896a122d7adcbedf0897cfd5acf62be3c5b63a71a4a425c8fe8474c0eb src/balance/model.rs
|
||||
41c3c020a60c372dbf965bd277c330dd9cf2ab079f6608b472adf72a656f4cb3 src/balance/pool_core.rs
|
||||
477132dd381e23f1be197c32ff58a0925f41d3e6aa63fe77c10973cefb2b76f6 src/balance/pool_selection.rs
|
||||
8abb6048303ee8c022546a528d5693167766e7450efd8e20f37ec6fd0fa9ef5e src/balance/pool_view.rs
|
||||
0a510955e55894c0a27679d0e8b80864924eb15278c8a70ba4f3ac0e6eae45ff src/balance/tests.rs
|
||||
da257fc249133fee657267192914701b115dd7a23ce6cd7423becca3a9b7e1dc src/balance/tests.rs
|
||||
5049d2bd01a9c866f3bad2288d8d594df96bba6045dfe15cd22b4173562b7388 src/basic_auth.rs
|
||||
9a8858b7ff461a4d961ba701ca3ed6eaec15c3f7f05eef8e0e30edc63617605a src/basic_auth/tests.rs
|
||||
7def03ace07dc38a4806277d75b6ce673d33ddaaf1c4855fa0a3372be1cf9489 src/cache/cold.rs
|
||||
@@ -366,14 +366,14 @@ b5856fd38a957b2ca9c7e3606d84d13d5cfcf3a45b487b15ae1d2dc248cbda57 src/proxy/body
|
||||
aa49c9928bb91e3d5bae0d340d88396a0417b9edec6192d41e1403533319a897 src/proxy/cache_http_invalidation.rs
|
||||
771cc1a38927f96e593b144dbab66cd64a5dc0ed42d54b1615c359845b2b7223 src/proxy/error_fallback.rs
|
||||
bf2e6bbd64fb45fceed54af0bff1c1e00da22b79c64dd8f5c23d2af0dbab0b7d src/proxy/forward/cache_lookup.rs
|
||||
2e76bb3ed7faf673208cac952385d8aec3b6d294dc06c9d5306aee2dca155b3a src/proxy/forward/response.rs
|
||||
cfa941b60b5d167ec9d8e2566ea3342b588d1a9078a6ca711ad6062ddf00fec9 src/proxy/forward/response.rs
|
||||
3b220cfa474325bfe7853d62daf2c71059d0dc582ac749fe61e2864094545d63 src/proxy/forward/route_cache.rs
|
||||
cea9e47ecb31b0e4c0bbe0eb83e0e53b5e7bdcb9930107b67a8c34eef01a3f49 src/proxy/forward/success_finish.rs
|
||||
902cbf8dc3c1ec8d25411bc7fe0400d301f3a7cc885afada594e4eaee3bedd08 src/proxy/forward/success_prepare.rs
|
||||
ce782dce2f7fe65ef93d08f88eb8277162ad9b975c1391da9c45869511196621 src/proxy/forward/upstream.rs
|
||||
b05c4f5c009c5e410f472ceaa999fa3a9c7fb60364d5b62de219f0924c9d524e src/proxy/forward/web_source.rs
|
||||
a9c011061585c067f04f7885215d53e6c40474bdced15d2be5a5ba65190910a0 src/proxy/forward_entry.rs
|
||||
31403d08d3f083118a95954d7ddb5144387b28a6a3336e6057721419d53356c9 src/proxy/h2_graceful.rs
|
||||
9b25f5e3ea4443a63ee6f45d12e1957dd316fe8e85325fc00ea416faaab1025a src/proxy/h2_graceful.rs
|
||||
c438066616527a3108f2ad53e3698ae9b2a80961714394cdd0a450c92f99d992 src/proxy/headers.rs
|
||||
5cb7522ceb9a9f083a15596ac4898559295e38d1138c80099577211de8a868ec src/proxy/headers/tests.rs
|
||||
8d17b97d90fd6a749ba8d37a8d28c94e6d7302b6c86905f073e2dc595506961a src/proxy/mod.rs
|
||||
@@ -381,7 +381,7 @@ c438066616527a3108f2ad53e3698ae9b2a80961714394cdd0a450c92f99d992 src/proxy/head
|
||||
ad701033f005c9c8c4b160f9b9b97bcabc17e936d8ade273a111937c483a125a src/proxy/tests/authority_tests.rs
|
||||
0f2eacadf1447db8aa1c1a78005aa262e0f747096bfe7e0a0e41a2cd31a0d17f src/proxy/tests/h3_navigation_tests.rs
|
||||
d134b0eb617f82f9971b3f3461379ea37c57bd0079bf54748d0c434b2ef1b475 src/proxy/tests/http_invalidation_tests.rs
|
||||
668a95def1865ddddcfb859f6dcfe70905e2c63d422268af32b4bdb5cd46d559 src/proxy/types.rs
|
||||
591b47fc40cbcb36d7c71998933dc873340dfcf2657e16c561ab64361c4dbab6 src/proxy/types.rs
|
||||
9999f717492755d62fc05cd5c1aff802ff0da901fe3e6b928bd8a000833c8799 src/proxy/upstream_helpers.rs
|
||||
2d9142e3ae95895b5271b4009ab48236a3a2074ce51179c021193b35777560e4 src/proxy/web_cache_revalidation.rs
|
||||
5af991311e4ed22cd8aaff15a4b9d45bb55fcdfcd0ebbfb4879dc1c7edf88ac4 src/proxy/web_cache_revalidation/tests.rs
|
||||
@@ -452,8 +452,8 @@ a4e1d2aa2913587c250f251356431097b76995aee6e8bf9e35c4978a95491de1 src/transform/
|
||||
8ed4baeaf79edfa2a84912cc00f1d13c564e1b997efe6888d2e4b5a16aaa8905 src/transform/tests.rs
|
||||
6146c59f36cf419623747d497b3de685da6c84964df43317bebdcb21deb9ee09 src/update_check.rs
|
||||
c42d000d1d576721af3ffe930589388693001b8113554a7658f6dcbc665b5d1b src/update_check/tests.rs
|
||||
14eadcadc7934831193a3e92a3c540817aaeb1ad239b8ca704127be1c728c61b src/upstream.rs
|
||||
2cb9098bce6aad7aa341d7d5bf6bbb9e816626c8ed24107e9587bdeec983fc9f src/upstream/client.rs
|
||||
92efcdaafb9f5a8514daf63d7fcde29be977d7bdcd90162eda0ce00d6967ffbd src/upstream.rs
|
||||
ca695e246bee5389b3757fe8588e48bff5d0ad473bc8588ad4ba7b52c99d7dfa src/upstream/client.rs
|
||||
ad29f3fc15c9b627b5d752af5adc9f99ee1364fec2df63f1e4509cb223988efb src/upstream/client_tests.rs
|
||||
75fef0a488d3f3dabfa03c2eabc5995442dfb3c9a1fde8eb6653a124dda25d43 src/upstream/protocol_tests.rs
|
||||
8a112154b9631f62a54584302a3ff6a64e4f177ce79aba678b4cb23e466c6ea3 src/upstream/tests.rs
|
||||
@@ -499,6 +499,8 @@ e5c58fc9b7685ec911bfa86f6ca4f0cc97c19a90c0cff5b60ea9887f1afe9ced tools/checks/a
|
||||
0060f8217640403c6af2d5091fdc9087d0fb2fc30cd545a3c58277a396d8121c tools/checks/admin_public_origin_0314_sim.mjs
|
||||
fd082812411cff7afb71b2289a6f1a469b8d3c8a7cfdcdd9e567a2a4baf81be4 tools/checks/admin_surface_audit_0310.py
|
||||
c9d0bef4b8ed7a2f49b0fad3e116cace62d3e6e1ca31e02a3073d1fdde5157d8 tools/checks/admin_themes_0323_ui_test.mjs
|
||||
e6462ce0fee8adb96ba22e275eb8cc1662c3bdf2e5ff53e7e0c8a55c8ce936ab tools/checks/appearance_density_buttons_0327.py
|
||||
b305998e8314bf79fe087ccd37676dd6f7139b88559e7c1132acdb646cb3631a tools/checks/appearance_density_buttons_0327_browser.py
|
||||
5b7d146a4558b2435fb4e8813db9e20e446988003fff884b3e132b28d926fa3c tools/checks/appearance_ux_0323_browser.py
|
||||
8b6e1a355cae58901118b399fa2d165f7e3fd8465c89cac82776906b8b23f0a6 tools/checks/appearance_ux_0323_ui_test.mjs
|
||||
f3dba206c60cd2e6fcc5f4a2c8d652ccf47362694448312cc1f8dc4112d93e7e tools/checks/backend_cache_0297_ui_test.mjs
|
||||
@@ -507,9 +509,9 @@ e82765ae946461952e68369f0b16f0a99f01e625bd61d2551513504f7b2f4d46 tools/checks/b
|
||||
a135c9456143975279f18233caab44b8c64f5025ef4ceeb1f2ad22090b588019 tools/checks/backend_protocol_0326_ui_test.mjs
|
||||
72e20f15a029d1a3596c7d05979354eb78dacd1de979f6933aed0994cfe76179 tools/checks/certificate_api_0319.py
|
||||
526d16db9de7be414a64483a1e9276d4a4402e3c7efd2479f79d01cc5b388f46 tools/checks/certificate_api_0319_ui_test.mjs
|
||||
562774d341ea63390399553b2f91f7d48536b2ace504aed27afd131e64b07787 tools/checks/check_source.py
|
||||
941eacd99d652916901ef3230e6e3c8489121a1676646413283e59093f8ad9c0 tools/checks/check_source.py
|
||||
a1ac2ab24958c6e8527c7797f224f94e765abd7173d4e5085a64362b193112c1 tools/checks/dashboard_appearance_ribbon_0326_browser.py
|
||||
0ab28370c06b2258321e20d27d63098c339fd9dc3b6f62aef6f5266c81ff28b5 tools/checks/dashboard_appearance_ribbon_0326_ui_test.mjs
|
||||
3729e4e4332ebb1b943c502e432845d6ae852ca971cdd04bc204813c9c81e016 tools/checks/dashboard_appearance_ribbon_0326_ui_test.mjs
|
||||
dc4df51fc15d4b6345c6625890ddbe014103851ebfa16abc583fbb0d809f4015 tools/checks/dashboard_boot_0311_ui_test.mjs
|
||||
7508f232a9e48049002dd4c9f34f9737bc92d304c51219f50430578dbc721855 tools/checks/dashboard_inline_layout_0323_ui_test.mjs
|
||||
dba768a42247cdd01863a032cf7ba223a52240285e70b0f7a0abd4a2e68c5fa1 tools/checks/dashboard_layout_editor_0323_ui_test.mjs
|
||||
@@ -527,20 +529,20 @@ fb8619444edf81afa604194f750dc76335394a73c74324eda59e392874f29ee8 tools/checks/i
|
||||
4f7821e7e25b09ce251d25a0b3fb4d8ce8396c36a5ed971c2637aeb325425909 tools/checks/langs_check.py
|
||||
c56a7763250f8cf1ac011feb0c90a06309bd680aeb6da6e1d1f825fbb2a573aa tools/checks/live_diagnostics_0326_browser.py
|
||||
a8bda904a92f9436761db1460f14da3c0c9b3db9edeeee581497700242784d64 tools/checks/memory_contracts.py
|
||||
c0f08ee32fb506e946a2cf3308c061da7351e6022337aa9114b21d7ad19203c8 tools/checks/mobile_protocol_0326.py
|
||||
ce4fb1793eeb76ccb888af48bf92312638ea7b056250d3a9328f47919a0958e7 tools/checks/mobile_protocol_0326.py
|
||||
db40b3940989dd6e32459574b4a5ba3219ebec8e2e68dea1f71ec4a9e53e78b0 tools/checks/mobile_protocol_0326_browser.py
|
||||
af98579ee942e774d88775c261ac351847c28bb4a5396dc67e458bd6b1ff7963 tools/checks/origin_resume_0313_ui_test.mjs
|
||||
0387a9e29244b58cf37a6673a88ae2b7fea3aa965c032423f3783a84eab4ba05 tools/checks/overview_0321_layout_regression.mjs
|
||||
7fda61ae66a6e3f1ada1304440c09e1f43d0e577b3a5eac8331afe86fc5eebcb tools/checks/overview_extra_metrics_0323_ui_test.mjs
|
||||
48dd1e13b83dc897c735028c93e17200cf4ed9ce175475dc5641ec3236569c38 tools/checks/overview_grid_spacing_0323_browser.py
|
||||
d530cb9b783d6e7ea3afd400a35a64865d16e11800bbf8910cb7edb9648f5510 tools/checks/overview_gutters_0324_browser.py
|
||||
0575423efc24465d276226f45e3b9ef4d2dd1ae0bfbb58e257a10b2184a17d2a tools/checks/overview_gutters_0324_browser.py
|
||||
b565aef4594265350240c24067a554f91fd605d0e920c03eef0b5b62c3934aad tools/checks/overview_registry_0323_ui_test.mjs
|
||||
f450e97dccf75c24e228e696f21ed4ae826a823ea4edde2429894a6b6b36eaab tools/checks/overview_uniform_grid_0323_ui_test.mjs
|
||||
644ca805fd7072a3087cfb8c4a41fc53eefe0e902e5d1524d8f892657970493f tools/checks/overview_wide_masonry_0323_ui_test.mjs
|
||||
1ac812929c2a8c0699ae3bdebd0d7e05b5bcaf86c87533bb669b5ba7955e3245 tools/checks/panel_cache_http_0310_ui_test.mjs
|
||||
8ff6d76ba2465794135b532358ec6fe448928293adcc64fffa3cd917f5c11662 tools/checks/passive_h2_0327.py
|
||||
eea7cdc9c7d8dd0f5fb079cfff657a6feadfc0b856f63265bfbd8257f1beca19 tools/checks/preflight.py
|
||||
cd3e039edc20b7baa558eb131e227827edc04a0155cdb85ac456cd3a5aa378fa tools/checks/preserve_host_0324.py
|
||||
964253df6a6143a0a6bfeeba05bbb57f8eaedf7746125c9e230e265403ac1983 tools/checks/preserve_host_0324.py
|
||||
3352941648add6d8a8044c0b5cad6bf264546d38c884a5beed64cd95addd850c tools/checks/preserve_host_0324_ui_test.mjs
|
||||
64984e55d93617ac61c83f19b91a2f70402057a47a1962dcbcfd0b7d904f6098 tools/checks/rate_pause_0326_ui_test.mjs
|
||||
599e0fa12fe95c7087a25801a26a590bbb473f24f038e0be157449daecec5593 tools/checks/refresh_0310_ui_test.mjs
|
||||
@@ -548,7 +550,7 @@ c11583dad0899f8b945cae6e2f6cb0bdb55f5526bd5f42c248ac41badec83679 tools/checks/r
|
||||
b84b66a6f8f63cd0a354ef607b96ff60c77ef37f80f49ea9a9036b33147c0b6a tools/checks/release_0317_ui_test.mjs
|
||||
333d4974a08c8d86155522a24037bdb9a21e578b32770cf0fcff2f3192209775 tools/checks/release_0318.py
|
||||
e73afc62214e9092c180730f624a2039ac3fc850dcd865b2b117c11f7caaf88b tools/checks/release_0318_ui_test.mjs
|
||||
c917a0b0e53178b25e0cb7d73c98d4add58533a09514b814b18037edba11b257 tools/checks/release_smoke.py
|
||||
ebfd4ced216bd0eac26bcb47fade5590759520b821af928df196c06ac1d2c7f3 tools/checks/release_smoke.py
|
||||
31b31e976962e2c53e0f1f71bf67f7d2686d30cb26f638defa1bd7636cf1c1e8 tools/checks/rust_module_contracts.py
|
||||
ecfe0bb21a7549225a19b0846bb6de8c99cbfbbf5a706d33cf84db2c7146abed tools/checks/rust_source.py
|
||||
adf84a983e0dbba228e47d71ec2d5c9964f7ca9989d5139de58f96ee961b035a tools/checks/security_contracts.py
|
||||
|
||||
@@ -101,6 +101,7 @@ if [[ "$mode" == "test" ]]; then
|
||||
python3 tools/checks/upstream_protocols_0323.py
|
||||
python3 tools/checks/preserve_host_0324.py
|
||||
python3 tools/checks/dynamic_acl_0325.py
|
||||
python3 tools/checks/appearance_density_buttons_0327.py
|
||||
python3 tools/checks/mobile_protocol_0326.py
|
||||
python3 tools/checks/check_source.py
|
||||
python3 tools/checks/release_smoke.py
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
RustProxy routes diagnostics according to the **Error file** switch under Settings > Logging. When the file is enabled, `ERROR` and `WARN` events, including PHP-FPM stderr and Rust worker panics, go to the configured error file rather than also being printed to the systemd journal. When the file is disabled (the default), those events go to the console/stderr (journald under systemd). `INFO` and lower-severity messages continue to use the console and any independently configured access sinks are unaffected.
|
||||
|
||||
A graceful upstream HTTP/2 `GOAWAY(NO_ERROR)` may coincide with a Hyper `Canceled -> connection closed` error. RustProxy treats the cancel as expected H2 churn **only when** it is correlated with a recently observed graceful GOAWAY on that backend client (one-second window). Safe empty methods may retry once. An unrecovered request remains an HTTP 502 and retains its detailed access/error context; its redundant upstream diagnostic uses `TRACE`, not `DEBUG`. Uncorrelated cancellations still follow normal error processing and may influence Passive Health. The text `connection closed` alone is not evidence of a graceful GOAWAY. This is not a global error-log suppression rule.
|
||||
|
||||
## Configuration
|
||||
|
||||
The settings document contains:
|
||||
|
||||
@@ -48,6 +48,10 @@ existing visual layout editor for drag-and-drop arrangement. Reordering and
|
||||
visibility still save through `/api/preferences` per account; this UI-only
|
||||
change does not alter server polling, proxy routing or backend metrics.
|
||||
|
||||
### Overview controls and density (0.32.7 development follow-up)
|
||||
|
||||
**Refresh now**, **Arrange Overview**, **Unlock layout**, **Visual Overview editor** and **Show all cards** inherit the same Normal/Compact button size rules as other buttons. Responsive placement still adapts to narrow screens, but no independent font-size, padding or height override applies. Dashboard density more clearly adjusts numeric tile sizing, inline chart height and the padding/title size of non-table Overview panels; the common tile gutters are unchanged. Button style and dashboard density remain independent per-account preferences.
|
||||
|
||||
## Refresh preferences (0.31.0)
|
||||
|
||||
**Settings -> Appearance -> Data refresh** saves an additional `refresh` object in the existing `admin_preferences` document for the signed-in account. It does not modify proxy configuration or create any migration. Older documents, including partially populated `refresh` objects, use defaults. Browser and server enforce exact allowed values:
|
||||
|
||||
@@ -1,278 +0,0 @@
|
||||
# Verification report - RustProxy 0.32.7
|
||||
|
||||
## 0.32.7 graceful upstream H2 close and backend health (pending runtime acceptance)
|
||||
|
||||
- Source changes: restrict GOAWAY(NO_ERROR) classification to Hyper's peer-
|
||||
initiated debug variant. Recycle exactly the observed upstream pool generation
|
||||
and replay only one empty GET/HEAD/OPTIONS request. No unsafe/body replay.
|
||||
- Correlate immediate cancelled `connection closed` events with a recent
|
||||
graceful GOAWAY within one second; all other I/O errors retain Passive
|
||||
Health counting. De-duplicate I/O failure observations within 250 ms.
|
||||
- Passive-ejected backends are readmitted after consecutive healthy active
|
||||
probes (minimum two) or, with active monitoring disabled, after a cooldown
|
||||
and a half-open request. Active failures still block routing.
|
||||
- On an actual healthy-to-unhealthy transition write WARN with the first
|
||||
counted error in the streak and the threshold-triggering error. The existing
|
||||
Error log must be enabled for these events to be persisted in `error.log`;
|
||||
otherwise WARN remains visible in stderr/journal. File-sink writes are
|
||||
best-effort and may fall back to stderr on backpressure or I/O failure.
|
||||
- Checks executed for this archive: `tools/checks/passive_h2_0327.py`
|
||||
**PASS** (source assertions), `tools/checks/docs_check.py` **PASS**,
|
||||
`tools/checks/release_0318.py` **PASS**, ZIP CRC and SHA256SUMS
|
||||
verification **PASS** (579 checksummed source files). These do **not**
|
||||
compile or execute RustProxy.
|
||||
- `./dev.sh check` returned 127 (Cargo unavailable). `./dev.sh test`
|
||||
stopped on a stale `preserve_host_0324.py` CSS-gap assertion; the
|
||||
unchanged 0.32.6 source fails that same test. `check_source.py` also
|
||||
stops on a pre-existing Revision History dialog CSS selector assertion
|
||||
in **both** unmodified 0.32.6 and patched 0.32.7 trees. Neither is
|
||||
evidence of a regression in this patch, but the complete test gate
|
||||
remains **open**.
|
||||
- **Not yet production-accepted:** no Rust compiler exists in this authoring
|
||||
environment. `cargo check`, `cargo test`, `cargo fmt` and live Nginx H2
|
||||
GOAWAY/HTTP1.1 ALPN behavior must be verified on a Rust-enabled host.
|
||||
|
||||
## 0.32.6 development follow-up — compact Appearance Dashboard layout
|
||||
|
||||
- The previous right-half, wrapping Overview card list left most of the screen
|
||||
empty and grew excessively tall with the 62-card registry. Moved Dashboard
|
||||
density to a compact full-width row and made the selector a full-width,
|
||||
single-line horizontal ribbon. Added previous/next browsing, a **Show all**
|
||||
expanded grid, horizontal earlier/later order buttons and Polish/English
|
||||
strings. Every existing toggle, order save, visual editor and account-scoped
|
||||
`/api/preferences` path remains intact.
|
||||
- Chromium fixture with real CSS, real 62-card renderer and mocked preferences:
|
||||
at 1500px, the default ribbon is 47px high and the Appearance dashboard
|
||||
section about 274px high; at 393px, the ribbon is 47px, the section about
|
||||
419px, and there is no page-level horizontal overflow. Programmatic browse,
|
||||
visibility-toggle, retained scroll position and expand/collapse all passed.
|
||||
`tools/checks/dashboard_appearance_ribbon_0326_browser.py` reproduces this
|
||||
test. This is a simulated interface test, not a compiled Rust or iOS Safari test.
|
||||
- Source/Node checks additionally verify translations, all card IDs and the
|
||||
unchanged preference persistence calls. Full Rust build and physical iOS
|
||||
acceptance remain pending.
|
||||
|
||||
|
||||
## 0.32.6 development follow-up — logo right-edge spacing
|
||||
|
||||
- Corrected the previous logo-spacing adjustment: the desired clearance is
|
||||
between the final `p` glyph and the **right border of the logo frame**,
|
||||
not between `/` and `p`. Removed extra slash margins and added a 2px
|
||||
right-side flex-box inset without changing the frame size or color.
|
||||
- Browser regression checks the text glyph's bounding rectangle against the
|
||||
frame at desktop and mobile widths; Chromium measures approximately 5px
|
||||
clearance compared with approximately 2px before correction. This does not
|
||||
require Rust compilation or imply a physical iOS Safari verification.
|
||||
|
||||
## 0.32.6 development follow-up — live diagnostic charts / mobile scroll
|
||||
|
||||
- The existing server diagnostics collector samples OS and process metrics in
|
||||
the background, with a 2-second idle delay between collection passes
|
||||
(sampling work can add time). Compact live status / SSE now
|
||||
exposes its **cached** `live_system` (sample timestamp, host/process CPU,
|
||||
process RSS, aggregate RX/TX rates and interface rates), without invoking a
|
||||
new OS measurement or fetching `/api/system-info` on each live event.
|
||||
- Live Overview charts use the administrator's `overview_seconds` (default **3**,
|
||||
accepted 1/2/3/5/10, including existing persisted 2-second preferences).
|
||||
Process/System *detail text* still updates only with the configured
|
||||
`system_info_seconds` (default **60**). Network chart RX/TX now reflects
|
||||
recently sampled interface rates rather than 60-second-old repeated values.
|
||||
- Disabled the nested `overflow:auto` network-interface list on narrow
|
||||
Overview containers. Stable SVG/text DOM remains in place, to reduce
|
||||
unexpected WebKit touch/momentum scroll anchoring. This is a mitigation;
|
||||
the exact source of the iOS 27 jump remains unverified on physical Safari.
|
||||
- Protocol badge Origin uses the same control radius as the adjacent policy
|
||||
pills for custom presets, and the same 0px baseline for the default preset;
|
||||
observed green/unknown neutral colors are unchanged.
|
||||
- `live_diagnostics_0326_browser.py`: real diagnostic renderer with 35 live
|
||||
updates verifies fast chart data and slow Process details, no chart DOM
|
||||
replacement or scroll movement, no extra sample from a slow-system-only
|
||||
refresh, touch-sized network list and both custom/default badge radii.
|
||||
`mobile_protocol_0326_browser.py` covers all custom radii at six widths.
|
||||
- Prior source/UI tests: all pre-Cargo checks passed; compilation and Rust
|
||||
integration tests not run (Cargo absent). The Chromium fixture does **not**
|
||||
establish Safari/iOS 27 acceptance.
|
||||
|
||||
## 0.32.6 development follow-up — suspended rate charts
|
||||
|
||||
- Added `src/admin/web/app/rate-sampling.js` to the authenticated Rust
|
||||
administration bundle. The shared policy records tab background/pagehide
|
||||
epochs and ignores intervals longer than three configured refresh periods
|
||||
(at least 10 seconds). It validates counter monotonicity and declines
|
||||
counter-derived rates across the gap, preserving existing history.
|
||||
- Updated Cache HIT/MISS/BYPASS, Transform metrics, Overview HTTP/protocol/
|
||||
cache-outcome deltas, optional small/wide rate and share charts, HTTP
|
||||
backend monitor, Stream traffic and Vhost/Stream detailed charts. Fresh
|
||||
absolute CPU/RAM/system observations and independent system-info reads
|
||||
retain their previous behavior. Visible missing rates show `-`, not `0/s`.
|
||||
- Added `tools/checks/rate_pause_0326_ui_test.mjs`: real Cache/Transform
|
||||
chart functions with a simulated DOM and clock. Tests normal idle 0/s,
|
||||
long gaps, short hide/show, pagehide/BFCache, counter resets, sample
|
||||
continuity and 30-second refresh support. This is not a live Safari test.
|
||||
- **Pending:** Cargo checks/compilation, real server/SSE data, mobile Safari
|
||||
tab suspension and BFCache tests.
|
||||
|
||||
## 0.32.6 development follow-up — badge grouping and chart cadence
|
||||
|
||||
- Moved each observed upstream HTTP protocol badge into its Vhost's existing
|
||||
`vhost-policy-pills` row; preserved the badge class, observed flag, green
|
||||
and neutral CSS styling. No backend or preference changes.
|
||||
- Kept network-interface rows and SVGs stable (no replacement on ordinary
|
||||
refresh), but restored **frequent** history progression: each Overview live
|
||||
status appends the latest cached interface rates, exactly as the aggregate
|
||||
network chart does. A system-info-only refresh updates visible rates but does
|
||||
not append a history point. System measurements are fetched only on the
|
||||
configured `system_info_seconds` cadence; no extra API call was added.
|
||||
- Chromium tests: `ios_scroll_0326_browser.py` (45 live renders, unchanged
|
||||
DOM/scroll/Process height, latest-value reuse and a system-info-only redraw);
|
||||
`vhost_protocol_badge_group_0326_browser.py` (real Vhost render at 393/1024px,
|
||||
observed green and unknown neutral colors); static source and Node.js protocol
|
||||
status checks. `mobile_protocol_0326_browser.py` also passed at six
|
||||
mobile widths (320-550px). `./dev.sh test` passed all pre-Cargo checks,
|
||||
including its source/SQL/upgrade/release-smoke and Node.js UI stages, then
|
||||
exited **127** at the missing-Cargo guard; Rust compilation/tests were not run.
|
||||
These results do **not** establish iOS 27 Safari acceptance or a compiled
|
||||
RustProxy binary.
|
||||
|
||||
## 0.32.6 development follow-up — iOS 27 scroll / CSS transform
|
||||
|
||||
- User video shows repeated returns toward Process during mobile scrolling;
|
||||
it does not include finger touch input, so exact root cause cannot be proven
|
||||
by visual inspection alone. The Network diagnostics renderer removed and
|
||||
recreated all interface rows/SVGs on every live sample, potentially
|
||||
invalidating WebKit's scroll anchor directly beneath Process.
|
||||
- Initially changed to update chart contents, text nodes and SVG points in place
|
||||
without replacing interface rows. An interim build appended interface RX/TX
|
||||
history only on new system measurements; this sampling decision was superseded
|
||||
by the later development follow-up above, which restores live-rate chart
|
||||
progression independently of slow system-data acquisition. Retest physical
|
||||
iOS 27 before declaring the scroll problem fixed.
|
||||
- CSS transformer preserves descendant pseudo-class combinators; admin pages
|
||||
carry `Cache-Control: no-transform`. Rust/Cargo check still pending.
|
||||
|
||||
## 0.32.6 mobile presentation and upstream protocol visibility
|
||||
|
||||
- `./dev.sh test` passed all pre-Cargo source, regression, simulated API,
|
||||
upgrade/release-smoke, SQL/schema, documentation, localization and Node.js UI
|
||||
checks. It then stopped at the expected missing-Cargo guard (`exit 127`).
|
||||
`./dev.sh check` also stopped there (`exit 127`). A production Rust build
|
||||
and execution of Rust unit tests **have not been performed**.
|
||||
- `tools/checks/mobile_protocol_0326_browser.py`,
|
||||
`appearance_ux_0323_browser.py` and `overview_grid_spacing_0323_browser.py`
|
||||
passed separately with headless Chromium. These optional browser tests
|
||||
require Playwright and are not a dependency of `./dev.sh test`.
|
||||
- Shipped static CSS and real 62-card grid tested under Chromium mobile touch
|
||||
emulation at 320, 375, 393, 402, 430 and 550px: two metric columns, no
|
||||
horizontal overflow, stable viewport scroll positions after metric updates
|
||||
and repeated no-op preference application. **This does not test Safari on
|
||||
a physical iPhone 17 Pro.**
|
||||
- Global Appearance radius presets in Chromium tested on vhost, backend badge,
|
||||
entity and metric surfaces; square draft dock remains excluded.
|
||||
- JavaScript Vhost badge test checks fresh H1/H2 response observations, Auto
|
||||
no-observation and stale states, response counters and isolation across
|
||||
vhosts with identical member IDs.
|
||||
- Rust test added to assert response-version observation and counters. **The
|
||||
Rust compiler and a running HTTP peer are absent; this is source coverage,
|
||||
not a completed Rust unit/integration test.**
|
||||
- Tests do not establish real backend HTTP/2 ALPN operation; staging validation
|
||||
and full Rust acceptance remain required before production use.
|
||||
|
||||
## Previous 0.32.5 verification history
|
||||
|
||||
- **0.32.5 administration UI startup fix:** the DNS ACL translation helper in
|
||||
`src/admin/web/management.js` is now initialized before the DDNS hint uses
|
||||
it. `tools/checks/dynamic_acl_startup_0325_ui_test.mjs` executes the real ACL
|
||||
editor initializer with a simulated DOM and verifies that it completes and
|
||||
renders the translatable DNS hint. The test reproduced the user-reported
|
||||
`ReferenceError` against the unmodified 0.32.5 source before the fix.
|
||||
**36/36 JavaScript checks passed** after adding this test to `dev.sh`.
|
||||
The assembled JavaScript bundle passed `node --check`. The source/version,
|
||||
admin surface, security, docs and language checks passed. `release_smoke.py`
|
||||
exceeded the available execution timeout; the Rust compiler and live server
|
||||
remain unavailable, so full release/runtime acceptance is not claimed.
|
||||
- **0.32.5 build correction:** fix reported Rust `E0505` in `src/acl/dynamic.rs` by cloning the hostname into `lookup_name` for `lookup_host`. The original `name` is returned as the cache key. Added a source-contract regression check; Rust compilation is still required to confirm the correction.
|
||||
- `tools/checks/dynamic_acl_0325.py`: **15/15 static source contracts passed**.
|
||||
- JavaScript dashboard/settings regression scripts: **36/36 passed** (35 existing and one new startup regression).
|
||||
- `tools/checks/check_source.py`, `rust_module_contracts.py`,
|
||||
`docs_check.py`, `langs_check.py`, `security_contracts.py`, and
|
||||
`admin_surface_audit_0310.py`: passed.
|
||||
- The full `./dev.sh test` was interrupted by the environment time limit while
|
||||
running expensive pre-Cargo release simulations. It was **not** a full pass.
|
||||
- Cargo/rustc are unavailable here. Dynamic DNS Rust unit tests, integration
|
||||
tests, real resolver timeouts/rotation and production acceptance **not run**.
|
||||
|
||||
## 0.32.5 dynamic DNS ACL changes
|
||||
|
||||
This build extends existing ACL `Rule.network` entries with allow-only DNS/DDNS
|
||||
hostname support. Resolution is background-only and bounded (60s cadence,
|
||||
4s timeout, max 8 concurrent lookups, max 128 unique names / 32 IPs per name).
|
||||
Initial, expired and failed resolution states deny dynamic host authorization.
|
||||
Existing numeric IP/CIDR and explicit-deny precedence remain unchanged.
|
||||
|
||||
A Rust compiler and real DNS peer were not available in this environment.
|
||||
The Rust tests in `src/acl/tests.rs` and `src/acl/dynamic.rs` **have not been
|
||||
executed** here. Before rollout, run `cargo fmt --all -- --check`,
|
||||
`cargo check --locked --all-targets` and `cargo test --locked`, then confirm
|
||||
live DDNS rotation and fail-closed DNS outages on staging.
|
||||
|
||||
## Previous 0.32.4 scope
|
||||
|
||||
Review of the supplied RustProxy 0.32.3 source and patch to 0.32.4:
|
||||
HTTP Host / HTTP/2 authority parity, explicit TCP/DNS destination and TLS/SNI
|
||||
isolation, relaxed HTTPS-by-IP troubleshooting hint, and uniform Overview gutters.
|
||||
Follow-up patch to the first 0.32.4 archive:
|
||||
- Fix reported `E0382` in `src/proxy/types.rs`: `Request::builder().uri(uri)`
|
||||
moved `uri` before `upstream_request_target(&uri, ...)` could borrow it.
|
||||
`.uri(uri.clone())` preserves the original URI for authority selection.
|
||||
- Make normal Overview gutters uniformly 4px (dense 3px, comfortable 12px).
|
||||
Resolve the higher-specificity `html[data-dashboard-density] .stats-grid`
|
||||
rule which otherwise overrode the aligned grid and kept the larger gaps.
|
||||
Existing database/configuration schemas and retry/transport policies are
|
||||
unchanged. Only compiling Rust and live protocol tests prove runtime behavior.
|
||||
|
||||
## Available checks
|
||||
|
||||
- `./dev.sh test`: **all pre-Cargo checks passed**, including source/security,
|
||||
SQLite migration/upgrade/backup simulations, memory-model scripts and **35
|
||||
Node.js UI/behavior test scripts**. The command then exited **127** because
|
||||
Rust/Cargo is not installed; this is **not** a passing Rust test run.
|
||||
- New `preserve_host_0324.py` and `preserve_host_0324_ui_test.mjs` passed:
|
||||
authority/destination split source contracts, four protocol selectors,
|
||||
verified/unencrypted origin warnings, explicit diagnostics preset.
|
||||
- Expanded Chromium CSS fixture `tools/checks/overview_gutters_0324_browser.py`:
|
||||
**27 checks passed** (3 container widths x 3 UI density modes x 3 Dashboard
|
||||
densities), checking horizontal/vertical gutters, equally high rows and
|
||||
numeric-to-large-card transition. Normal/dense/comfortable gaps measured
|
||||
**4/3/12px** and the outer grid bottom margin remained `0px`.
|
||||
The older `overview_grid_spacing_0323_browser.py` also passed with all
|
||||
62 blocks, responsive breakpoints and browser zoom 90%-130%.
|
||||
These are simulated layout tests, not a live administrator session.
|
||||
- `preserve_host_0324.py` now guards against moving `uri` before its final
|
||||
authority adjustment, in addition to the backend/transport source contracts.
|
||||
The existing Rust unit test for retry authority remains in the source.
|
||||
- Version consistency: Cargo manifest, package root in existing lockfile,
|
||||
OpenAPI, README, release notes and static assertion fixtures updated to 0.32.4.
|
||||
External Cargo dependency resolutions have **not** been regenerated.
|
||||
|
||||
## Rust validation not performed (blocking for production)
|
||||
|
||||
The user's Rust compiler reported `error[E0382]: borrow of moved value: uri`
|
||||
from the first 0.32.4 archive. This has been corrected in source, but **the
|
||||
corrected code has not been compiled here**: no Cargo or Rust compiler is
|
||||
available in the source-editing environment.
|
||||
Do not treat static tests or the simulated TLS-peer tests added to Rust source
|
||||
as evidence that RustProxy builds or that an actual Angie backend accepts the
|
||||
corrected requests. Run, on a Rust 1.99+ host:
|
||||
|
||||
```sh
|
||||
cargo fmt --all -- --check
|
||||
cargo check --locked --all-targets
|
||||
cargo test --locked
|
||||
```
|
||||
|
||||
Then validate on staging with HTTPS-by-IP and `preserve_host: true` for
|
||||
HTTP/1.1, Auto (H2 and H1 ALPN), compatible HTTP/2 and strict H2; check
|
||||
`:authority` vs `Host`, SNI, certificate verification, WebSockets, H2C and
|
||||
HTTP health probe `host` overrides. Inspect Angie response/error logs for
|
||||
400 responses and verify backend connectivity through pool rotation/retry.
|
||||
No claim of universal backend compatibility or measured throughput is made.
|
||||
+42
-20
@@ -8798,7 +8798,7 @@ html[data-dashboard-density=ultra] #panel-overview .stats-grid {
|
||||
}
|
||||
|
||||
html[data-dashboard-density=normal] #panel-overview .stat {
|
||||
padding: 12px 13px;
|
||||
padding: 14px 14px;
|
||||
}
|
||||
|
||||
html[data-dashboard-density=normal] #panel-overview .stat>span {
|
||||
@@ -8806,8 +8806,8 @@ html[data-dashboard-density=normal] #panel-overview .stat>span {
|
||||
}
|
||||
|
||||
html[data-dashboard-density=normal] #panel-overview .stat strong {
|
||||
font-size: 25px;
|
||||
margin: 5px 0 3px;
|
||||
font-size: 26px;
|
||||
margin: 6px 0 4px;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
@@ -8816,7 +8816,7 @@ html[data-dashboard-density=normal] #panel-overview .stat small {
|
||||
}
|
||||
|
||||
html[data-dashboard-density=compact] #panel-overview .stat {
|
||||
padding: 10px 11px;
|
||||
padding: 9px 10px;
|
||||
}
|
||||
|
||||
html[data-dashboard-density=compact] #panel-overview .stat>span {
|
||||
@@ -8825,8 +8825,8 @@ html[data-dashboard-density=compact] #panel-overview .stat>span {
|
||||
}
|
||||
|
||||
html[data-dashboard-density=compact] #panel-overview .stat strong {
|
||||
font-size: 25px;
|
||||
margin: 4px 0 2px;
|
||||
font-size: 22px;
|
||||
margin: 3px 0 2px;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
@@ -8860,7 +8860,17 @@ html[data-dashboard-density=ultra] #panel-overview .stat small {
|
||||
}
|
||||
|
||||
html[data-dashboard-density=ultra] #panel-overview .stat-chart svg {
|
||||
height: 38px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
/* Dashboard density applies to charts and panels as well as number tiles.
|
||||
Keep the Overview grid gutters independent of dashboard density. */
|
||||
html[data-dashboard-density=normal] #panel-overview .stat-chart svg {
|
||||
height: 34px;
|
||||
}
|
||||
|
||||
html[data-dashboard-density=compact] #panel-overview .stat-chart svg {
|
||||
height: 28px;
|
||||
}
|
||||
|
||||
html[data-table-density=compact] :is(table th, table td) {
|
||||
@@ -9529,7 +9539,6 @@ html[data-chart-style] :is(#workspace, dialog) svg polyline {
|
||||
}
|
||||
|
||||
.page-intro-title-row>:is(.quiet, .outline) {
|
||||
min-height: 35px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@@ -9555,7 +9564,6 @@ html[data-chart-style] :is(#workspace, dialog) svg polyline {
|
||||
.page-intro-title-row>:is(.quiet, .outline) {
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
padding: 7px 9px;
|
||||
white-space: normal;
|
||||
text-align: center;
|
||||
}
|
||||
@@ -9567,9 +9575,6 @@ html[data-chart-style] :is(#workspace, dialog) svg polyline {
|
||||
letter-spacing: -.6px
|
||||
}
|
||||
|
||||
.page-intro-title-row>:is(.quiet, .outline) {
|
||||
font-size: 11px;
|
||||
}
|
||||
}
|
||||
|
||||
.system-info-heading-actions {
|
||||
@@ -10850,9 +10855,12 @@ html[data-chart-style] :is(#workspace, dialog) svg polyline {
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
html[data-dashboard-density=compact] #panel-overview .dashboard-overview-grid.is-aligned>.stat strong,
|
||||
html[data-dashboard-density=normal] #panel-overview .dashboard-overview-grid.is-aligned>.stat strong {
|
||||
font-size: calc(clamp(18px, 5.5vw, 25px));
|
||||
font-size: clamp(20px, 5.8vw, 26px);
|
||||
}
|
||||
|
||||
html[data-dashboard-density=compact] #panel-overview .dashboard-overview-grid.is-aligned>.stat strong {
|
||||
font-size: clamp(19px, 5vw, 22px);
|
||||
}
|
||||
|
||||
#panel-overview .dashboard-overview-grid.is-aligned>.card:not(.pool-card) {
|
||||
@@ -10869,6 +10877,26 @@ html[data-chart-style] :is(#workspace, dialog) svg polyline {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
html[data-dashboard-density=normal] #panel-overview .dashboard-overview-grid>.card:not(.pool-card) {
|
||||
padding: 13px;
|
||||
}
|
||||
|
||||
html[data-dashboard-density=compact] #panel-overview .dashboard-overview-grid>.card:not(.pool-card) {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
html[data-dashboard-density=ultra] #panel-overview .dashboard-overview-grid>.card:not(.pool-card) {
|
||||
padding: 7px;
|
||||
}
|
||||
|
||||
html[data-dashboard-density=compact] #panel-overview .dashboard-overview-grid>.card .card-heading h2 {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
html[data-dashboard-density=ultra] #panel-overview .dashboard-overview-grid>.card .card-heading h2 {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
#panel-overview .overview-wide-chart .card-heading {
|
||||
min-width: 0;
|
||||
align-items: baseline;
|
||||
@@ -11105,14 +11133,8 @@ html[data-chart-style] :is(#workspace, dialog) svg polyline {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.dashboard-widget-settings-controls>button {
|
||||
min-height: 30px;
|
||||
padding: 5px 10px;
|
||||
}
|
||||
|
||||
.dashboard-widget-settings-controls>.dashboard-widget-scroll-button {
|
||||
min-width: 30px;
|
||||
padding-inline: 6px;
|
||||
}
|
||||
|
||||
.dashboard-widget-settings-controls .dashboard-layout-open-settings {
|
||||
|
||||
@@ -22,16 +22,18 @@
|
||||
let elapsed = upstream_started.elapsed();
|
||||
let connect_failure = cause.is_connect();
|
||||
let detail = upstream_failure_detail(&cause, &active_backend, elapsed, connect_failure);
|
||||
let failure_class =
|
||||
upstream_health_error_class(&cause, connect_failure, &active_backend);
|
||||
let graceful_h2_close = matches!(
|
||||
failure_class,
|
||||
"h2_graceful_goaway" | "h2_graceful_close"
|
||||
);
|
||||
if let Some(exchange) = &exchange {
|
||||
exchange.websocket_error("upstream_request_failed", "upstream_http_error");
|
||||
*exchange.upstream_error.lock().unwrap_or_else(|e| e.into_inner()) = Some(detail.clone());
|
||||
}
|
||||
if let Some(lease) = &active_lease {
|
||||
lease.error_detail(
|
||||
upstream_health_error_class(&cause, connect_failure, &active_backend),
|
||||
&detail,
|
||||
final_attempt_elapsed,
|
||||
);
|
||||
lease.error_detail(failure_class, &detail, final_attempt_elapsed);
|
||||
}
|
||||
if connect_failure {
|
||||
tracing::warn!(
|
||||
@@ -43,6 +45,17 @@
|
||||
error = %detail,
|
||||
"upstream connection failed"
|
||||
);
|
||||
} else if graceful_h2_close {
|
||||
// Correlated GOAWAY(NO_ERROR) is expected connection churn. Keep
|
||||
// failed requests visible as 502/access-log entries, but avoid
|
||||
// repeating their verbose diagnostic at DEBUG severity.
|
||||
tracing::trace!(
|
||||
backend = %active_backend.id,
|
||||
origin = %active_backend.origin,
|
||||
elapsed_ms = elapsed.as_millis(),
|
||||
error = %detail,
|
||||
"upstream H2 graceful close left an unrecovered request"
|
||||
);
|
||||
} else {
|
||||
tracing::debug!(
|
||||
backend = %active_backend.id,
|
||||
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Static regression for 0.32.7 follow-up; not a browser or Rust runtime test."""
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
css = (ROOT / 'src/admin/web/style.css').read_text()
|
||||
html = (ROOT / 'src/admin/web/index.html').read_text()
|
||||
response = (ROOT / 'src/proxy/forward/response.rs').read_text()
|
||||
helper = (ROOT / 'src/proxy/h2_graceful.rs').read_text()
|
||||
for button_id in ['overview-refresh', 'overview-layout-open', 'overview-layout-unlock',
|
||||
'overview-layout-open-settings', 'dashboard-widget-expand']:
|
||||
assert f'id="{button_id}"' in html
|
||||
assert '.page-intro-title-row>:is(.quiet, .outline) {\n min-height:' not in css
|
||||
assert 'dashboard-widget-settings-controls>button {\n min-height:' not in css
|
||||
assert 'html[data-button-style=compact] body' in css
|
||||
for mode in ['normal', 'compact', 'ultra']:
|
||||
assert f'html[data-dashboard-density={mode}] #panel-overview .dashboard-overview-grid>.card:not(.pool-card)' in css
|
||||
assert 'upstream_health_error_class(&cause, connect_failure, &active_backend)' in response
|
||||
assert 'let graceful_h2_close = matches!(' in response
|
||||
assert 'tracing::trace!(' in response
|
||||
assert 'StatusCode::BAD_GATEWAY' in response
|
||||
assert 'Some(detail.clone())' in response
|
||||
assert 'recently_saw_graceful_goaway()' in helper
|
||||
print('PASS: shared button CSS, density variants, guarded graceful-H2 logging (source only)')
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Optional Chromium regression: shared button sizing and Dashboard density.
|
||||
|
||||
Uses the production HTML button markup and stylesheet without a running API.
|
||||
Run: python3 tools/checks/appearance_density_buttons_0327_browser.py
|
||||
"""
|
||||
from pathlib import Path
|
||||
import re
|
||||
import shutil
|
||||
from playwright.sync_api import sync_playwright
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
index = (ROOT / 'src/admin/web/index.html').read_text()
|
||||
css = (ROOT / 'src/admin/web/style.css').read_text()
|
||||
|
||||
|
||||
def button(button_id):
|
||||
match = re.search(r'<button\b(?=[^>]*\bid="' + re.escape(button_id) + r'")[\s\S]*?</button>', index)
|
||||
assert match, button_id
|
||||
return match.group(0).replace(' hidden', '')
|
||||
|
||||
|
||||
html = f'''<!doctype html><html data-theme="dark"><head><meta name="viewport" content="width=device-width, initial-scale=1"><style>{css}</style></head>
|
||||
<body><main style="max-width:100%;padding:10px;box-sizing:border-box">
|
||||
<div class="page-intro-title-row"><h1>Overview</h1>
|
||||
{button('overview-refresh')}{button('overview-layout-open')}{button('overview-layout-unlock')}</div>
|
||||
<div class="appearance-settings-grid dashboard-appearance-grid"><div class="dashboard-widget-settings"><div class="dashboard-widget-settings-controls">
|
||||
{button('overview-layout-open-settings')}{button('dashboard-widget-expand')}
|
||||
</div></div></div>
|
||||
<div>{'<button class="quiet" id="reference-quiet">Reference</button><button class="outline" id="reference-outline">Reference</button>'}</div>
|
||||
<section id="panel-overview"><div class="stats-grid dashboard-overview-grid is-aligned">
|
||||
<article class="stat stat-chart" data-dashboard-widget="http_protocol"><span>Requests</span><strong>100</strong><small>Rate</small><svg viewBox="0 0 100 25"></svg></article>
|
||||
<article class="card" data-dashboard-widget="diagnostics"><div class="card-heading"><h2>Diagnostics</h2></div><p>Metrics</p></article>
|
||||
</div></section></main></body></html>'''
|
||||
|
||||
with sync_playwright() as p:
|
||||
browser = p.chromium.launch(executable_path=shutil.which('chromium') or shutil.which('chromium-browser'), args=['--no-sandbox'])
|
||||
for width in [320, 393, 1280]:
|
||||
page = browser.new_page(viewport={'width': width, 'height': 900})
|
||||
page.set_content(html)
|
||||
for style in ['normal', 'compact']:
|
||||
page.evaluate('(value) => document.documentElement.dataset.buttonStyle = value', style)
|
||||
computed = page.evaluate('''() => {
|
||||
const values = id => {
|
||||
const s = getComputedStyle(document.getElementById(id));
|
||||
return [s.fontSize, s.minHeight, s.paddingTop, s.paddingRight, s.paddingBottom, s.paddingLeft];
|
||||
};
|
||||
return Object.fromEntries(['overview-refresh', 'overview-layout-open', 'overview-layout-unlock',
|
||||
'overview-layout-open-settings', 'dashboard-widget-expand', 'reference-quiet', 'reference-outline']
|
||||
.map(id => [id, values(id)]));
|
||||
}''')
|
||||
for target, reference in [
|
||||
('overview-refresh', 'reference-quiet'),
|
||||
('overview-layout-open', 'reference-quiet'),
|
||||
('overview-layout-unlock', 'reference-outline'),
|
||||
('overview-layout-open-settings', 'reference-outline'),
|
||||
('dashboard-widget-expand', 'reference-quiet'),
|
||||
]:
|
||||
assert computed[target] == computed[reference], (width, style, target, computed[target], computed[reference])
|
||||
print('PASS buttons', width, style, computed['overview-refresh'])
|
||||
measures = {}
|
||||
for density in ['normal', 'compact', 'ultra']:
|
||||
page.evaluate('(value) => document.documentElement.dataset.dashboardDensity = value', density)
|
||||
measures[density] = page.evaluate('''() => {
|
||||
const stat = document.querySelector('#panel-overview .stat');
|
||||
const value = stat.querySelector('strong');
|
||||
const svg = stat.querySelector('svg');
|
||||
const card = document.querySelector('#panel-overview .card');
|
||||
const title = card.querySelector('h2');
|
||||
return {statPadding: parseFloat(getComputedStyle(stat).paddingTop),
|
||||
valueSize: parseFloat(getComputedStyle(value).fontSize),
|
||||
chartHeight: parseFloat(getComputedStyle(svg).height),
|
||||
cardPadding: parseFloat(getComputedStyle(card).paddingTop),
|
||||
titleSize: parseFloat(getComputedStyle(title).fontSize),
|
||||
overflow: document.documentElement.scrollWidth > window.innerWidth};
|
||||
}''')
|
||||
assert not measures[density]['overflow'], (width, density)
|
||||
for key in ['statPadding', 'valueSize', 'chartHeight', 'cardPadding', 'titleSize']:
|
||||
values = [measures[d][key] for d in ['normal', 'compact', 'ultra']]
|
||||
assert values[0] > values[1] > values[2], (width, key, values)
|
||||
print('PASS densities', width, measures)
|
||||
page.close()
|
||||
browser.close()
|
||||
@@ -150,7 +150,7 @@ for marker in [
|
||||
assert "data" in (root / ".dockerignore").read_text().splitlines()
|
||||
css = (root / "src/admin/web/style.css").read_text()
|
||||
assert ".logging-grid fieldset" not in css, "logging sinks must reuse shared card styling"
|
||||
assert re.search(r"dialog\.config-history-dialog,\s*dialog\.config-history-json-dialog\s*\{", css), "Revision History and JSON comparison must use shared dialog styling"
|
||||
assert re.search(r"dialog\.config-history-dialog,\s*dialog\.config-history-json-dialog,\s*dialog\.logs-dialog,", css), "Revision History and JSON comparison must use shared dialog styling"
|
||||
assert ".config-history-dialog::backdrop" not in css, "Revision History must not duplicate the shared dialog backdrop"
|
||||
history_dialog_css = re.search(r"^\.config-history-dialog\s*\{([^}]*)\}", css, re.M).group(1)
|
||||
assert "border-radius:" not in history_dialog_css, "Revision History dialog must stay square-cornered"
|
||||
@@ -229,7 +229,7 @@ for marker in ['toggleVhostEnabled', 'vhQuickEnable', 'vhQuickDisable', 'backend
|
||||
assert 'rustproxy-backend-table-v1' not in vhosts_js and 'poolTablePreferenceKey' not in vhosts_js
|
||||
assert 'window.rustProxyPreferences.update({' in vhosts_js and 'backend_table_sort' in vhosts_js and 'backend_table_descending' in vhosts_js
|
||||
style_ui = (root / 'src/admin/web/style.css').read_text()
|
||||
for marker in ['--scrollbar-thumb', '*::-webkit-scrollbar-thumb', '.backend-table-tools', '.vh-enable-control', '.vhost-quick-toggle', '.dashboard-widget-toggle', '--toolbar-control-height: min(var(--button-min-height), var(--ui-field-min-height))', 'height: var(--toolbar-control-height)']:
|
||||
for marker in ['--scrollbar-thumb', '::-webkit-scrollbar-thumb', '.backend-table-tools', '.vh-enable-control', '.vhost-quick-toggle', '.dashboard-widget-toggle', '--toolbar-control-height: min(var(--button-min-height), var(--ui-field-min-height))', 'height: var(--toolbar-control-height)']:
|
||||
assert marker in style_ui, marker
|
||||
preferences_js = (root / "src/admin/web/app/preferences.js").read_text()
|
||||
assert 'dashboard-widget-toggle' in preferences_js and 'visible.type = "checkbox"' not in preferences_js
|
||||
|
||||
@@ -18,7 +18,7 @@ assert.match(css, /\.appearance-settings-grid\.dashboard-appearance-grid\s*\{[^}
|
||||
assert.match(css, /\.dashboard-appearance-grid \.dashboard-widget-list\s*\{[^}]*flex-wrap:\s*nowrap;[^}]*overflow-x:\s*auto;/s,
|
||||
'the default card selector must be a horizontal ribbon, not a tall two-column list');
|
||||
assert.match(css, /\.dashboard-appearance-grid \.dashboard-widget-list\.is-expanded\s*\{[^}]*display:\s*grid;/s);
|
||||
assert.match(css, /\.dashboard-widget-settings-controls > \.dashboard-widget-scroll-button/);
|
||||
assert.match(css, /\.dashboard-widget-settings-controls\s*>\s*\.dashboard-widget-scroll-button/);
|
||||
assert(js.includes('list.scrollLeft = previousScroll'), 'rebuilding settings must preserve horizontal scroll position');
|
||||
assert(js.includes('focusedId') && js.includes('preventScroll: true'), 'keyboard focus must survive updates');
|
||||
assert(js.includes('saveAppearancePreference({ dashboard_hidden_widgets:') &&
|
||||
|
||||
@@ -15,8 +15,8 @@ assert 'grid-template-columns: repeat(2, minmax(0, 1fr))' in css
|
||||
assert '@container overview-canvas (max-width: 700px)' in css
|
||||
assert 'overview-canvas (max-width: 440px)' not in css
|
||||
assert '.vhost-backend-protocol-badge' in css
|
||||
assert '.vhost-card' in css[css.index('/* Global shape preference.'):]
|
||||
assert '.draft-dock,' not in css[css.index('/* Global shape preference.'):]
|
||||
assert '.vhost-card' in css[css.index('html:is([data-corner-style=square]'):]
|
||||
assert '.draft-dock,' not in css[css.index('html:is([data-corner-style=square]'):]
|
||||
assert 'grid.append(...orderedNodes)' in preferences
|
||||
assert 'orderedNodes.some((node, index) => node !== currentNodes[index])' in preferences
|
||||
assert 'if (ordered.some((node, i) => node !== previous[i])) grid.append(...ordered);' in masonry
|
||||
@@ -31,8 +31,8 @@ policy_block=render[policy_start:policy_end]
|
||||
assert 'policy.append(badge);' in policy_block
|
||||
assert 'vhost-backend-protocol-badge' in policy_block
|
||||
assert 'box.append(badges)' not in render
|
||||
assert '.vhost-backend-protocol-badge[data-observed="true"]' in css
|
||||
assert 'color: var(--green)' in css[css.index('.vhost-backend-protocol-badge[data-observed="true"]'):]
|
||||
assert '.vhost-backend-protocol-badge[data-observed=true]' in css
|
||||
assert 'color: var(--green)' in css[css.index('.vhost-backend-protocol-badge[data-observed=true]'):]
|
||||
assert 'self.inner.observe_protocol(value.version())' in client
|
||||
assert '"upstream_protocol_observed"' in pool
|
||||
print('PASS: mobile grid, shape, stable reorder and observed backend protocol source contracts')
|
||||
@@ -56,7 +56,7 @@ with sync_playwright() as playwright:
|
||||
for card_density in ("normal", "compact", "ultra"):
|
||||
page.evaluate("d => document.documentElement.dataset.dashboardDensity = d", card_density)
|
||||
data = page.evaluate(snapshot)
|
||||
expected = max(3, old_gap - 1)
|
||||
expected = old_gap
|
||||
assert abs(data["parentGap"] - old_gap) < 0.01, data
|
||||
assert abs(data["rowGap"] - expected) < 0.01, data
|
||||
assert abs(data["columnGap"] - expected) < 0.01, data
|
||||
|
||||
@@ -42,7 +42,7 @@ css=read('src/admin/web/style.css')
|
||||
match=re.search(r'#panel-overview \.dashboard-overview-grid\.is-aligned\s*\{([^}]*)\}',css)
|
||||
assert match
|
||||
rules=match[1]
|
||||
for marker in ['margin: 0;', '--overview-gap: max(3px, calc(var(--ui-gap) - 1px));',
|
||||
for marker in ['margin: 0;', '--overview-gap: var(--ui-gap);',
|
||||
'row-gap: var(--overview-gap);', 'column-gap: var(--overview-gap);',
|
||||
'gap: var(--overview-gap);']:
|
||||
assert marker in rules, marker
|
||||
|
||||
@@ -448,7 +448,7 @@ def ui_contract_smoke() -> None:
|
||||
assert './dev.sh tls deploy' not in document_text
|
||||
assert '/opt/rustproxy/current/rust-proxy --data-dir /var/lib/rustproxy tls deploy' in document_text
|
||||
style = (ROOT / "src/admin/web/style.css").read_text(encoding="utf-8")
|
||||
for marker in ['--scrollbar-thumb', '*::-webkit-scrollbar-thumb', '.backend-table-tools', '.vhost-quick-toggle', '.dashboard-widget-toggle', '--toolbar-control-height: min(var(--button-min-height), var(--ui-field-min-height))', 'height: var(--toolbar-control-height)']:
|
||||
for marker in ['--scrollbar-thumb', '::-webkit-scrollbar-thumb', '.backend-table-tools', '.vhost-quick-toggle', '.dashboard-widget-toggle', '--toolbar-control-height: min(var(--button-min-height), var(--ui-field-min-height))', 'height: var(--toolbar-control-height)']:
|
||||
assert marker in style, marker
|
||||
assert "pool-vhost-disabled" in vhosts
|
||||
for marker in ["locationMatchRegex", "headersVisualBuilder", "headersAdvancedJson", "openLocationHelp", "cloudflare-client-ip", "timing-headers"]:
|
||||
|
||||
Reference in new issue
Block a user