v0.25.6
This commit is contained in:
1 parent
c819f0a335
commit
e1a59f6e56
53 files changed
+817
-380
No files matched your search
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
Read README.md, ROADMAP.md and docs/TEST_REPORT.md before making changes.
|
Read README.md, ROADMAP.md and docs/TEST_REPORT.md before making changes.
|
||||||
The project name is RustProxy; the Cargo package/binary remains `rust-proxy` for
|
The project name is RustProxy; the Cargo package/binary remains `rust-proxy` for
|
||||||
compatibility. Current source version: 0.25.5.
|
compatibility. Current source version: 0.25.6.
|
||||||
|
|
||||||
## Delivery
|
## Delivery
|
||||||
|
|
||||||
|
|||||||
@@ -4,8 +4,15 @@
|
|||||||
> test-only changes and packaging implementation notes were moved to
|
> test-only changes and packaging implementation notes were moved to
|
||||||
> [`docs/CHANGELOG_TECHNICAL_ARCHIVE.md`](docs/CHANGELOG_TECHNICAL_ARCHIVE.md).
|
> [`docs/CHANGELOG_TECHNICAL_ARCHIVE.md`](docs/CHANGELOG_TECHNICAL_ARCHIVE.md).
|
||||||
|
|
||||||
|
## 0.25.6
|
||||||
|
|
||||||
|
- Show upstream Hyper client generation, request budget progress, generation age and rotation count in the live **Backends** diagnostics table, sourced from the same `/api/events` status snapshots as the existing backend metrics.
|
||||||
|
- Retain the configurable backend client generation recycling and HTTP/1 buffer ceiling introduced in 0.25.5.
|
||||||
|
- Keep SQLite schema 8 and the existing configuration format; no migration is required from 0.25.5.
|
||||||
|
|
||||||
## 0.25.5
|
## 0.25.5
|
||||||
|
|
||||||
|
- Bound long-lived backend Hyper client generations with configurable request-count and age recycling, add a configurable upstream HTTP/1 read-buffer ceiling, and expose per-backend rotation diagnostics without reloading vhosts or purging cache.
|
||||||
- Expand Prometheus/Grafana coverage with bounded Traffic analytics for countries, fixed User-Agent families, methods, status classes, cache outcomes, routes and serving source; add explicit built-in Web Server inventory/source metrics while keeping raw IPs, paths and full User-Agent values out of Prometheus labels.
|
- Expand Prometheus/Grafana coverage with bounded Traffic analytics for countries, fixed User-Agent families, methods, status classes, cache outcomes, routes and serving source; add explicit built-in Web Server inventory/source metrics while keeping raw IPs, paths and full User-Agent values out of Prometheus labels.
|
||||||
- Add an About dialog in the dashboard top bar with project author, open-source notice and source repository link; rename the top-bar Docs action to Documentation.
|
- Add an About dialog in the dashboard top bar with project author, open-source notice and source repository link; rename the top-bar Docs action to Documentation.
|
||||||
- Replace the always-expanded mobile dashboard navigation with a compact on-demand Menu control that closes after section selection, Escape or an outside click; desktop navigation is unchanged.
|
- Replace the always-expanded mobile dashboard navigation with a compact on-demand Menu control that closes after section selection, Escape or an outside click; desktop navigation is unchanged.
|
||||||
|
|||||||
Generated
+1
-1
@@ -1688,7 +1688,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rust-proxy"
|
name = "rust-proxy"
|
||||||
version = "0.25.5"
|
version = "0.25.6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"arc-swap",
|
"arc-swap",
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "rust-proxy"
|
name = "rust-proxy"
|
||||||
version = "0.25.5"
|
version = "0.25.6"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
rust-version = "1.88"
|
rust-version = "1.88"
|
||||||
description = "RustProxy - independent reverse proxy with local administration"
|
description = "RustProxy - independent reverse proxy with local administration"
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
# RustProxy 0.25.5
|
# RustProxy 0.25.6
|
||||||
|
|
||||||
Independent Rust reverse proxy and static Web Server with a dashboard, SQLite configuration,
|
Independent Rust reverse proxy and static Web Server with a dashboard, SQLite configuration,
|
||||||
streaming HTTP/TLS/WebSocket forwarding, raw TCP/UDP stream hosts, IP-bound vhosts and backend pools.
|
streaming HTTP/TLS/WebSocket forwarding, raw TCP/UDP stream hosts, IP-bound vhosts and backend pools.
|
||||||
|
|
||||||
**0.25.5 release source.**
|
**0.25.6 release source.**
|
||||||
|
|
||||||
## Layer-4 streams
|
## Layer-4 streams
|
||||||
|
|
||||||
@@ -11,14 +11,13 @@ Raw TCP/UDP forwarding has its own **Streams** page in the primary navigation, a
|
|||||||
|
|
||||||
Named HTTP/HTTPS listener bind addresses use the same chip-style editor as vhost hostnames, including multi-address listeners.
|
Named HTTP/HTTPS listener bind addresses use the same chip-style editor as vhost hostnames, including multi-address listeners.
|
||||||
|
|
||||||
## What changed in 0.25.5
|
## What changed in 0.25.6
|
||||||
|
|
||||||
- Align the **Revision history** modal with the shared dashboard dialog styling: square corners, shared backdrop/window rules and no duplicated modal-only appearance declarations.
|
- Show backend Hyper client generation, generation request count, generation age and total rotations directly in the live **Backends** diagnostics table. The table consumes the same status snapshots delivered by `/api/events`, so these fields refresh alongside Active/Requests/Errors/Latency/Traffic without a second polling path.
|
||||||
- When a vhost enables verified Cloudflare client-IP mode, accept `CF-IPCountry` only from a direct Cloudflare edge and use that trusted country for country analytics/log capture and country policy evaluation. Invalid, duplicate, unknown or absent values fall back to the local GeoIP lookup of the verified effective client IP.
|
- Keep the 0.25.5 bounded backend-client behavior: each backend client generation is recycled after 25,000 requests or one hour by default, with a 128 KiB upstream HTTP/1 adaptive read-buffer ceiling. All three limits remain configurable per vhost/backend and recycling does not reload the vhost or purge cache.
|
||||||
- Expand the dedicated Prometheus exporter and bundled Grafana dashboard with bounded Traffic analytics: countries, fixed User-Agent families, methods, status classes, cache outcomes, serving source, configured routes and built-in Web Server inventory/traffic. Raw client IPs, request paths and full User-Agent strings remain excluded from Prometheus labels.
|
- Keep SQLite schema 8 and the existing configuration format; upgrading from 0.25.5 requires no data migration.
|
||||||
- Keep SQLite schema 8 and all existing configuration formats; upgrading from 0.25.4 requires no data migration.
|
|
||||||
|
|
||||||
The 0.25.4 retained-history restore behavior remains unchanged. See [host access](docs/VHOST_ACCESS.md), [live logs and Traffic](docs/LIVE_LOGS.md), [documentation index](docs/README.md) and the [0.25.5 release audit](docs/V0.25.5_AUDIT.md). Open follow-up work is tracked separately in [TODO](docs/TODO.md).
|
The detailed 0.25.5 implementation audit remains available as historical baseline evidence. Current 0.25.6 verification status is maintained in [docs/TEST_REPORT.md](docs/TEST_REPORT.md).
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
@@ -95,7 +94,7 @@ CARGO_BUILD_JOBS=1 CARGO_PROFILE_RELEASE_LTO=false \
|
|||||||
CARGO_PROFILE_RELEASE_CODEGEN_UNITS=8 cargo build --release --locked
|
CARGO_PROFILE_RELEASE_CODEGEN_UNITS=8 cargo build --release --locked
|
||||||
```
|
```
|
||||||
|
|
||||||
The 0.25.5 source archive preserves the resolved `Cargo.lock` supplied with the source tree and
|
The 0.25.6 source archive preserves the resolved `Cargo.lock` supplied with the source tree and
|
||||||
updates only this package's own version entry. This packaging environment has no Cargo, so the
|
updates only this package's own version entry. This packaging environment has no Cargo, so the
|
||||||
dependency graph was not re-resolved here. On the compiler-enabled deployment host, run the
|
dependency graph was not re-resolved here. On the compiler-enabled deployment host, run the
|
||||||
locked check/test/release gates below and retain the verified lockfile. `dev.sh` can generate a
|
locked check/test/release gates below and retain the verified lockfile. `dev.sh` can generate a
|
||||||
@@ -334,7 +333,7 @@ python3 scripts/release_smoke.py
|
|||||||
# Runs those checks first, then the Rust suite when Cargo is available:
|
# Runs those checks first, then the Rust suite when Cargo is available:
|
||||||
bash dev.sh test
|
bash dev.sh test
|
||||||
# Source-only package, with no Git checkout required:
|
# Source-only package, with no Git checkout required:
|
||||||
python3 make_zip.py /tmp/RustProxy-0.25.5.zip
|
python3 make_zip.py /tmp/RustProxy-0.25.6.zip
|
||||||
```
|
```
|
||||||
|
|
||||||
## New management and test-origin guide
|
## New management and test-origin guide
|
||||||
|
|||||||
+10
@@ -1,5 +1,14 @@
|
|||||||
# RustProxy roadmap
|
# RustProxy roadmap
|
||||||
|
|
||||||
|
## 0.25.6 - Backend memory diagnostics visibility
|
||||||
|
|
||||||
|
Current direction: 0.25.5 -> 0.25.6
|
||||||
|
|
||||||
|
- [x] Show upstream client generation, current-generation request count, generation age and total rotations in the main Backends diagnostics table.
|
||||||
|
- [x] Reuse the existing `/api/events` status snapshot refresh path; do not add a second diagnostics polling loop.
|
||||||
|
- [x] Keep the 0.25.5 client-generation recycling defaults and configuration compatibility unchanged.
|
||||||
|
- [ ] Run compiler-enabled `cargo fmt --all`, `cargo check --locked --all-targets` and `cargo test --locked --all-targets` on a Rust release host.
|
||||||
|
|
||||||
## 0.25.5 - Traffic country consistency and Revision History styling
|
## 0.25.5 - Traffic country consistency and Revision History styling
|
||||||
|
|
||||||
Current direction: 0.25.4 -> 0.25.5
|
Current direction: 0.25.4 -> 0.25.5
|
||||||
@@ -10,6 +19,7 @@ Current direction: 0.25.4 -> 0.25.5
|
|||||||
- [x] Add Cloudflare-country trust regression coverage and release/source-contract checks.
|
- [x] Add Cloudflare-country trust regression coverage and release/source-contract checks.
|
||||||
- [x] Extend Prometheus with a live Traffic analytics collector, fixed-cardinality User-Agent/method/source families, country/top-route views and built-in Web Server inventory/source metrics.
|
- [x] Extend Prometheus with a live Traffic analytics collector, fixed-cardinality User-Agent/method/source families, country/top-route views and built-in Web Server inventory/source metrics.
|
||||||
- [x] Extend the bundled Grafana dashboard with a Traffic vhost filter, Web Server request rate, countries, User-Agent families, serving sources, methods, status classes, cache outcomes, capture-state gauges and configured routes.
|
- [x] Extend the bundled Grafana dashboard with a Traffic vhost filter, Web Server request rate, countries, User-Agent families, serving sources, methods, status classes, cache outcomes, capture-state gauges and configured routes.
|
||||||
|
- [x] Bound backend Hyper client lifetime with configurable request/age recycling and an upstream HTTP/1 buffer ceiling so sustained traffic can release pool/TLS high-water allocations without a vhost save.
|
||||||
- [ ] Run compiler-enabled `cargo fmt --all`, `cargo check --locked --all-targets` and `cargo test --locked --all-targets` on a Rust release host.
|
- [ ] Run compiler-enabled `cargo fmt --all`, `cargo check --locked --all-targets` and `cargo test --locked --all-targets` on a Rust release host.
|
||||||
|
|
||||||
## 0.25.4 - Configuration history restore
|
## 0.25.4 - Configuration history restore
|
||||||
|
|||||||
+147
-145
@@ -1,19 +1,19 @@
|
|||||||
61bf40a0572889dc8b0dda9eae4e93e44b0de9364b3c798106c85700ffb37c23 .dockerignore
|
61bf40a0572889dc8b0dda9eae4e93e44b0de9364b3c798106c85700ffb37c23 .dockerignore
|
||||||
4140a2956264b44f259e6a37fc00ba02097bbe68b09296e04d3d243c1287129b .env.example
|
4140a2956264b44f259e6a37fc00ba02097bbe68b09296e04d3d243c1287129b .env.example
|
||||||
9e6356475bf587091bab72246ec9e325b498f7e48a6220e9a18baa50d0a385a6 .gitignore
|
9e6356475bf587091bab72246ec9e325b498f7e48a6220e9a18baa50d0a385a6 .gitignore
|
||||||
6c4f8f8b1cb127854ce228dc6f93f7b45405bd156df50a712f3483624551cad9 AGENTS.md
|
95ac5b696f463eb9b491564a2658f9e9db56d0beb629eea47c0ec0dc81e361e5 AGENTS.md
|
||||||
1c7570cbd73a16f2ff581e014825a5f5fc2996c761c79e39f5e5985dfdc183d2 CHANGELOG.md
|
d9515bebfa7df5c0862e4fb1667017dc6d81c5e82e7383c55d9220a10e152372 CHANGELOG.md
|
||||||
e0337e1b205915bb9aa1c4e4c5302c582a29e92ce9d57bb94e973413f2a08ce0 Cargo.lock
|
22fb853ffef79b5f72f2b1c2818acae81b89511fdd5e2509b41c64883694a06a Cargo.lock
|
||||||
a3db5cdfac8f8602143f9bb625a1487c79f7524299215c20e16a52e492006d1f Cargo.toml
|
0a3790234bfadfcb178e26629be392d164ca0c86a7268ca9b12dd2713643819f Cargo.toml
|
||||||
d6d22ba63f4bc3d16a13012ecaabff8a156be57c824d2f20f66976502fb27d1f Dockerfile
|
d6d22ba63f4bc3d16a13012ecaabff8a156be57c824d2f20f66976502fb27d1f Dockerfile
|
||||||
d85b4765506884e0c03925998d675e10cdd4bed65a93c5525d0e2843b4236d73 README.md
|
a160ca8048f170a45da6abe57f886ee6e5416057ff158f5cbb12259b78b6adc8 README.md
|
||||||
94363612c185da471d32510da269aa54fd77b4bd012352ed169cc3bab399fac5 ROADMAP.md
|
3930c03cc27a1c441d976733b10783b6e36d037d691f75e5e7b569998ad8cd10 ROADMAP.md
|
||||||
da8311e3db945290666324a2f24bf4521b365272d7ac3f862ded1be993eea646 UPDATE_CHECK.toml
|
da8311e3db945290666324a2f24bf4521b365272d7ac3f862ded1be993eea646 UPDATE_CHECK.toml
|
||||||
928ba6a504bc431ae100c6e587861e5088b28822d2cb19da5d437b39d26c864a build.rs
|
928ba6a504bc431ae100c6e587861e5088b28822d2cb19da5d437b39d26c864a build.rs
|
||||||
e7064c2b7ac3c86a2e1f9c6c755665ad971588632287646f6e469dd4fca49b44 debian/README.md
|
a28b771e57632b7268a2e43bbf0447df564de522d1cacdc7cdf9aec766f653e7 debian/README.md
|
||||||
5ade138d66129988ac6ef4d4dd4677cb6e1d883bfa82fb0fd4913097f62431c4 debian/build-package.sh
|
e322e6b0412b42f906e1a554ddcf2427d2f71d6fb0fa7e999ecc590131662154 debian/build-package.sh
|
||||||
0763a4bd8b429f7922b23a7276ff694f3a751b83fb127f6ad7ec654e5e507ecd debian/build-repository.sh
|
0763a4bd8b429f7922b23a7276ff694f3a751b83fb127f6ad7ec654e5e507ecd debian/build-repository.sh
|
||||||
1cb1be86cc5e4de6feef9d4475a346161af710eba0022af2afb6146ec7e94736 debian/changelog
|
d6d6d3a1a1f350e8930974cb06b3abf712a0144e25589ff578ee589ee0685dd9 debian/changelog
|
||||||
c90457b19b1b2f7998d3db59a656d215eb0fab23769197405960457b66d95cf7 debian/control
|
c90457b19b1b2f7998d3db59a656d215eb0fab23769197405960457b66d95cf7 debian/control
|
||||||
dff2ecb9c14623416981f444bc6df1c4e2bf55d330260f36a312d8d42245400f debian/rules
|
dff2ecb9c14623416981f444bc6df1c4e2bf55d330260f36a312d8d42245400f debian/rules
|
||||||
c537d54fd92a9b97c5f6e6ec63bc1276cda324513e2946b341b2193f63b62e6a debian/rustproxy.environment
|
c537d54fd92a9b97c5f6e6ec63bc1276cda324513e2946b341b2193f63b62e6a debian/rustproxy.environment
|
||||||
@@ -24,7 +24,7 @@ cb0db03a2c1b06fa04a11f7690755a0ca90b17f19ed8fdb228810f505c48c78a debian/rustpro
|
|||||||
e8e18df40bcd69d6aa404282679186d9b8256ac63a5b4e80d7f081e8a0095a2e debian/source/format
|
e8e18df40bcd69d6aa404282679186d9b8256ac63a5b4e80d7f081e8a0095a2e debian/source/format
|
||||||
385ac7970fa94f043d0bcf04a91184e6e2c807587b85e55517ed064bb4bddba6 deploy/README.md
|
385ac7970fa94f043d0bcf04a91184e6e2c807587b85e55517ed064bb4bddba6 deploy/README.md
|
||||||
7b7fdf383bbaea4f37b5c120e98a24e9a075fba56ae7838a31a5152c7edcde02 deploy/rustproxy.service
|
7b7fdf383bbaea4f37b5c120e98a24e9a075fba56ae7838a31a5152c7edcde02 deploy/rustproxy.service
|
||||||
9d448d3a24eb529b1846a6bd7cd0a81a1b58a10ccf30c41d7b8db64b8099c727 dev.sh
|
18fb60f5f784389223ed7199e665d7033d51095fab2a3b13382401eec7ff5e7f dev.sh
|
||||||
5f51efe621f45512a466fa7f2656867c6502a135ca040f4bfeec06a6919b39b6 docker-agent/README.md
|
5f51efe621f45512a466fa7f2656867c6502a135ca040f4bfeec06a6919b39b6 docker-agent/README.md
|
||||||
7fee7d51a7deb67e73e53a0bdff3aa4630aea9bab9b23a0f9b8001b2169892b1 docker-agent/certificate.go
|
7fee7d51a7deb67e73e53a0bdff3aa4630aea9bab9b23a0f9b8001b2169892b1 docker-agent/certificate.go
|
||||||
5e4f565c3c9de4dba897af2e801ea646a83395e72eae4717a6d502dff2fcec10 docker-agent/docker-agent.env.example
|
5e4f565c3c9de4dba897af2e801ea646a83395e72eae4717a6d502dff2fcec10 docker-agent/docker-agent.env.example
|
||||||
@@ -33,28 +33,28 @@ bf687a851374d8f1fa59d050f3f76532f7c12f16a6daa7d3c36102c2d9a8ec9c docker-agent/d
|
|||||||
9d77c90767fa929ee8338734d72ce83284d3d965673270f62cb2b1613d587a33 docker-agent/install.sh
|
9d77c90767fa929ee8338734d72ce83284d3d965673270f62cb2b1613d587a33 docker-agent/install.sh
|
||||||
b68234472bec5cedd67c7cfe1de7d8806a965dfd4101f944aa6320132f18c14e docker-agent/main.go
|
b68234472bec5cedd67c7cfe1de7d8806a965dfd4101f944aa6320132f18c14e docker-agent/main.go
|
||||||
3d4051a1f805d145df3877476e4b87773e74be8e123045065955a5133afdc68c docker-agent/main_test.go
|
3d4051a1f805d145df3877476e4b87773e74be8e123045065955a5133afdc68c docker-agent/main_test.go
|
||||||
85f490ce949a3457d3cc48c38fc4f5357e069921ba3e64002b507632f862da5e docker-agent/model.go
|
7fd09ce19c86cf778eda55fc7b5943d70f650c656ffe0fc54f8e15a932a76578 docker-agent/model.go
|
||||||
e52b31d0abf65ae3034f6cb367cca113633014ce8d1d799ad4dd5624d2c7b8bb docker-agent/network.go
|
e52b31d0abf65ae3034f6cb367cca113633014ce8d1d799ad4dd5624d2c7b8bb docker-agent/network.go
|
||||||
634790f35ff4627df2a78cec2ed371f6e9ec9df00afb386075595fc7f3ed72eb docker-agent/rustproxy-docker-agent.service
|
634790f35ff4627df2a78cec2ed371f6e9ec9df00afb386075595fc7f3ed72eb docker-agent/rustproxy-docker-agent.service
|
||||||
5220d669171ec3ad65f50e0bc8de5178dadaa4904def8e1a4f61002aa9e9a55b docker-agent/server.go
|
5220d669171ec3ad65f50e0bc8de5178dadaa4904def8e1a4f61002aa9e9a55b docker-agent/server.go
|
||||||
802a30b793a6ae6a5046489612a23659f33d25e41d0794551381db202daac904 docs/ACME_PROVIDERS.md
|
802a30b793a6ae6a5046489612a23659f33d25e41d0794551381db202daac904 docs/ACME_PROVIDERS.md
|
||||||
ec15163f5f51c9212003b7edd1fc380321311c2496fbaa9b45c838281b9af475 docs/ACME_RFC2136.md
|
ec15163f5f51c9212003b7edd1fc380321311c2496fbaa9b45c838281b9af475 docs/ACME_RFC2136.md
|
||||||
710087c9d0fb4d466d66098c0a3e6a0bf5c1ec074ea751badb73e3e022626a0c docs/API.md
|
d699f2261a0d7854e49e9b8bae44fa37008a7d2f6340a73cdc37e840722ea211 docs/API.md
|
||||||
64f91768d214bc8ea460f39393b4492c4ad8d422cbab1421c0e308b35bb8fdb7 docs/API_ACCESS.md
|
8e2b592bfb631ace744a3e0c75e1a4f1d94164b6bce3fd6faf05a3d954edfd9a docs/API_ACCESS.md
|
||||||
0f7f159ad5b4b5277f80c19f3c47f4e7823ea439ef02e5913e1391f1b34d129f docs/ARCHITECTURE.md
|
0f7f159ad5b4b5277f80c19f3c47f4e7823ea439ef02e5913e1391f1b34d129f docs/ARCHITECTURE.md
|
||||||
cd2597465af031cdb47db802f8ad6d3af34ef9e79f679df906a7b84220ea3260 docs/CACHE.md
|
cd2597465af031cdb47db802f8ad6d3af34ef9e79f679df906a7b84220ea3260 docs/CACHE.md
|
||||||
c25f3f6763c35dacf718b4b87c5665c2030b1fb3584e8c20940fc3ca7a2d26a3 docs/CACHE_DIAGNOSTICS.md
|
9cb338ed07ac1f92ad491e2099a7e3af63e66262417b1fef24d98c6a791d13fa docs/CACHE_DIAGNOSTICS.md
|
||||||
f2f850b9500e7aa297337b54253f76fc3ceddad940a66c40332029adf32d124c docs/CHANGELOG_TECHNICAL_ARCHIVE.md
|
f2f850b9500e7aa297337b54253f76fc3ceddad940a66c40332029adf32d124c docs/CHANGELOG_TECHNICAL_ARCHIVE.md
|
||||||
db5534427ff0f004940fd6960906d3eaa75347a110e6322827c51c5d63f20adb docs/CONTAINER.md
|
db5534427ff0f004940fd6960906d3eaa75347a110e6322827c51c5d63f20adb docs/CONTAINER.md
|
||||||
9538a52d508d8d7053c1387c42eef60e6d5dc1879c300b6fe951b3374c16884c docs/CUSTOM_LOCATIONS.md
|
9538a52d508d8d7053c1387c42eef60e6d5dc1879c300b6fe951b3374c16884c docs/CUSTOM_LOCATIONS.md
|
||||||
7db65a96f696aff1d7f74e2041cfc6ecdf437b1412ece90cee26da1ceff4cf7e docs/DOCKER_DISCOVERY.md
|
7db65a96f696aff1d7f74e2041cfc6ecdf437b1412ece90cee26da1ceff4cf7e docs/DOCKER_DISCOVERY.md
|
||||||
9a882f07945b207d032936feb843f29467e4654f8255fa0104d988a54987f982 docs/ERROR_LOGGING.md
|
9a882f07945b207d032936feb843f29467e4654f8255fa0104d988a54987f982 docs/ERROR_LOGGING.md
|
||||||
df6ecd4a50796640243676ad4b3a87789f6e5d20cbebea6255e92fbfff1c7131 docs/HTTP3.md
|
df6ecd4a50796640243676ad4b3a87789f6e5d20cbebea6255e92fbfff1c7131 docs/HTTP3.md
|
||||||
6dee18b438c277dc22c28f4532872ef57be9060aed368dd2437741b36a1a8738 docs/INSTALL.md
|
4c27c3d7a7fca41fb325fcec5d86a883174eb4a3d11d5d6ac68912f9e8a17775 docs/INSTALL.md
|
||||||
3b5c31c805e5aee0dc2100b81246a9b631b5abb996faa598ae94f87ba39305f3 docs/INTEGRATIONS_040.md
|
3b5c31c805e5aee0dc2100b81246a9b631b5abb996faa598ae94f87ba39305f3 docs/INTEGRATIONS_040.md
|
||||||
b640a87349e125d1cce1b93caed06aeee09ef5acd0824d0ca1472757b696d477 docs/LIVE_LOGS.md
|
b640a87349e125d1cce1b93caed06aeee09ef5acd0824d0ca1472757b696d477 docs/LIVE_LOGS.md
|
||||||
7c35c4cdbe7bbb81d94f3bf6aeb22b8a866af3e7f0d62bbedc299e4d6f264e0d docs/MANAGEMENT.md
|
7c35c4cdbe7bbb81d94f3bf6aeb22b8a866af3e7f0d62bbedc299e4d6f264e0d docs/MANAGEMENT.md
|
||||||
b9d7ca444c894f22b3a13cbd9173c48fcc3e1e2f3c3a8f1f5fb635040101930e docs/MIGRATION.md
|
87608e2bd72a9fbeb611371064748ce33b4f21d7bc807af93c486fa53c5da244 docs/MIGRATION.md
|
||||||
5f090a190000c6badab2a74e5d4968e70c34de43b59c1452f5b05503b5c5c18a docs/MOCK_AUTH.md
|
5f090a190000c6badab2a74e5d4968e70c34de43b59c1452f5b05503b5c5c18a docs/MOCK_AUTH.md
|
||||||
1f85fac0e06e432ef6f744f0b5f9c1b7a27a1e9e1ad30dc1a218eab96b1caffe docs/MOCK_SERVER.md
|
1f85fac0e06e432ef6f744f0b5f9c1b7a27a1e9e1ad30dc1a218eab96b1caffe docs/MOCK_SERVER.md
|
||||||
e7516646dfb107d6240370f4e7460b1189f2eb21f398740381d5d102847bbfe6 docs/NOT_FOUND_HOSTS.md
|
e7516646dfb107d6240370f4e7460b1189f2eb21f398740381d5d102847bbfe6 docs/NOT_FOUND_HOSTS.md
|
||||||
@@ -71,10 +71,10 @@ a699fd663bfbf001525f22f0fbacdf03a58c5e825232d8d144e51cbb8b1008b2 docs/SECURITY.
|
|||||||
620b69e566d27af04f0604f4ca3f88cf95cdfea7fbc6ae9dd92446d2b2b5d9be docs/SECURITY_AUDIT.md
|
620b69e566d27af04f0604f4ca3f88cf95cdfea7fbc6ae9dd92446d2b2b5d9be docs/SECURITY_AUDIT.md
|
||||||
a2be253670072567459010b79f64df6093ccf9614aa249bdaa98917a83caeb31 docs/SETTINGS.md
|
a2be253670072567459010b79f64df6093ccf9614aa249bdaa98917a83caeb31 docs/SETTINGS.md
|
||||||
3611defd206cde107e75cac006159856d12cd8f15df7ae2eb9ec3592ed2b4abd docs/STREAMS.md
|
3611defd206cde107e75cac006159856d12cd8f15df7ae2eb9ec3592ed2b4abd docs/STREAMS.md
|
||||||
a471f700eca3d01e8e7bd477e05b93c57b40c10d169db32c3ed7232002dba327 docs/TEST_REPORT.md
|
71dbb8a13872ac9c1c5af5c63ffa44571e6d31bf4ae1ee6803c3373d1d8b1171 docs/TEST_REPORT.md
|
||||||
cfb452d8496839e832b5fbacdd4e52525b0ecc3112fbb62340c1e580bd5c1717 docs/TODO.md
|
cfb452d8496839e832b5fbacdd4e52525b0ecc3112fbb62340c1e580bd5c1717 docs/TODO.md
|
||||||
8ee6187a5460ca45643b7fd789e27bffd264449e3a92ff70e9359edee011bbbb docs/TRANSFORM.md
|
8ee6187a5460ca45643b7fd789e27bffd264449e3a92ff70e9359edee011bbbb docs/TRANSFORM.md
|
||||||
b02957b708174c9def830ced3c70c943a47af7a33467ef858255d04ab92c4af0 docs/TRANSPORT.md
|
a1e9c6d38d21067d1ce7115ca3395ae8ff1f6a4c40fb0ebf00a6940ef79df439 docs/TRANSPORT.md
|
||||||
96a6816915d526f00e261846131ee3f942ef332af996cf0f73c79ec1ba9f9c7a docs/V0.21.0_AUDIT.md
|
96a6816915d526f00e261846131ee3f942ef332af996cf0f73c79ec1ba9f9c7a docs/V0.21.0_AUDIT.md
|
||||||
0c1c3ba6e8724d85ec54e254e70bbf05e063db025280ef4af866b774fb43f76b docs/V0.22.0_AUDIT.md
|
0c1c3ba6e8724d85ec54e254e70bbf05e063db025280ef4af866b774fb43f76b docs/V0.22.0_AUDIT.md
|
||||||
3f811c457bf6be662969fbac32c3cfcc49b13c2f00d0125e4f2eeab768f59f0e docs/V0.22.1_AUDIT.md
|
3f811c457bf6be662969fbac32c3cfcc49b13c2f00d0125e4f2eeab768f59f0e docs/V0.22.1_AUDIT.md
|
||||||
@@ -99,7 +99,7 @@ d0e609febbcd1cfdb8ea0b00b4fa6f081eac01e2d43a81e38a53ae25783152cc docs/V0.24.8_A
|
|||||||
9dbb66e408bcd4d32267724e557fa9f7f44ef9b70db4ab170c61a7a839b7b157 docs/V0.25.3_AUDIT.md
|
9dbb66e408bcd4d32267724e557fa9f7f44ef9b70db4ab170c61a7a839b7b157 docs/V0.25.3_AUDIT.md
|
||||||
583d548b4a5db9f35a2bbf8ec00ec22397764c5850a8e883a3d12680da517df7 docs/V0.25.4_AUDIT.md
|
583d548b4a5db9f35a2bbf8ec00ec22397764c5850a8e883a3d12680da517df7 docs/V0.25.4_AUDIT.md
|
||||||
bf9b4cf4fec2c8ce287e1b3c2e7d4828e101dafe4d6c173f099819f22493d144 docs/V0.25.5_AUDIT.md
|
bf9b4cf4fec2c8ce287e1b3c2e7d4828e101dafe4d6c173f099819f22493d144 docs/V0.25.5_AUDIT.md
|
||||||
49a0ddd3071a480b331c108b718d497af9c2ec9844b3bfab5c01fbfab64c560d docs/VHOSTS.md
|
ce259052c023e90a7bfb6e39fe82e52b845a8b2a051bfa29883d29e87a9301a2 docs/VHOSTS.md
|
||||||
b979afd3d56731eeb06e9dc38d37730693e7fbf3aa78467932842c0e712e7b26 docs/VHOST_ACCESS.md
|
b979afd3d56731eeb06e9dc38d37730693e7fbf3aa78467932842c0e712e7b26 docs/VHOST_ACCESS.md
|
||||||
f0e76167944861517d1d42b9186ff0b2f184be0371b9e8597827e60895de4a76 docs/WEB_SERVER.md
|
f0e76167944861517d1d42b9186ff0b2f184be0371b9e8597827e60895de4a76 docs/WEB_SERVER.md
|
||||||
c336f998027330c58d5afbbbb3a3a682fd44ae3997643882fe342633822f8bb3 docs/screenshots/README.md
|
c336f998027330c58d5afbbbb3a3a682fd44ae3997643882fe342633822f8bb3 docs/screenshots/README.md
|
||||||
@@ -111,16 +111,16 @@ e31ac05a99615e4ea6c4c9a8b2e090968583fe3959f838a600b5740cb170f8c5 examples/confi
|
|||||||
b26833cb4251f9390a44192ecc827ff7f052fd19016a5ccf7498c94503ab4ce3 examples/mock-vhost.json
|
b26833cb4251f9390a44192ecc827ff7f052fd19016a5ccf7498c94503ab4ce3 examples/mock-vhost.json
|
||||||
134d4a59727b27accb3141d4cee26a4a74157d236de4996bfd682e639462b2b5 examples/tinyauth-vhost.json
|
134d4a59727b27accb3141d4cee26a4a74157d236de4996bfd682e639462b2b5 examples/tinyauth-vhost.json
|
||||||
5a8f3a8a054abc89c6e78896b9fe2f903212199a24dc3d2d2bcbd0696a31bcde examples/transport.json
|
5a8f3a8a054abc89c6e78896b9fe2f903212199a24dc3d2d2bcbd0696a31bcde examples/transport.json
|
||||||
17e7971fa9d9b141019fba3135d87cb1aa0cbc55d56b0718f879f880b615da26 examples/vhosts-balanced.json
|
d242de9614fbb52933b4accd32f4715ca94107abe4a3b1d7e088362b07a6ba60 examples/vhosts-balanced.json
|
||||||
e06905b6363103b1bcee1a09b9e02292033f114d88f3edbea22ddab53e9e5071 examples/vhosts-private.json
|
af2bdb1343a8141069e94ccd2c7f92574ad848437e2f9fdb5c7576a9a18ef4a5 examples/vhosts-private.json
|
||||||
64800051e89c3a0028eb17cd4b5ca3c52d4685e75b2dc610251ffeb2170f95fc grafana/README.md
|
05f196d7f6d52083b6eaad3b432305fbd70c4cef541f85355a275d4804dc879d grafana/README.md
|
||||||
1be61d025a8d922485659cf7fe10b72083378f2155eb50a849c10d3c82845a16 grafana/rustproxy-overview.json
|
dfe6b4a94349af6091e25a2b2635bbdce9143aa452c90efbcc10de1081a4ed15 grafana/rustproxy-overview.json
|
||||||
30763fc61c38992a44bc24ad6932b88fd3b322724fce799db1f17f9a747eb59a install-debian13.sh
|
30763fc61c38992a44bc24ad6932b88fd3b322724fce799db1f17f9a747eb59a install-debian13.sh
|
||||||
858b39fa6886b71d20690bf369e76580922364b3cc7f0cf6ba9b040df9cd76e3 install.sh
|
858b39fa6886b71d20690bf369e76580922364b3cc7f0cf6ba9b040df9cd76e3 install.sh
|
||||||
29cada0936762f26495064d1524a668262ed729b21f20aebddc8b6e5cfea363b langs/README.md
|
29cada0936762f26495064d1524a668262ed729b21f20aebddc8b6e5cfea363b langs/README.md
|
||||||
a3ce2c48ee034f037bad2f6cd3392bbc44470b1bd1a1ea3bfae4f8e81ae600de langs/en_US.json
|
70c1c370d906fa958293f9e4b5df7751f49104be115a40bdc0d5d4c479b5ca70 langs/en_US.json
|
||||||
13d376f3a55e5cbf6515f3bfe9543f67435f1f5fb4760ba120175c76b73dc05d langs/pl_pl.json
|
c469574e18e8abc8ec66806d03ab53499371e6c7ca3aa318aebc7b171ab8efb4 langs/pl_pl.json
|
||||||
c0603bb9a0248d6ee1af0fdc3eab745ed7b7251a0b6e499c0e6ed5761f3a52a4 make_zip.py
|
b650fd27159eab69c0fd4b27c541019a5ba48fcac120ad90a1195af2bcad1b23 make_zip.py
|
||||||
e830d37dd1f81a4b0aa7d535f5bba69e34e433b0fd99cc8ee0b296786c32379a migrations/0002_admin.sql
|
e830d37dd1f81a4b0aa7d535f5bba69e34e433b0fd99cc8ee0b296786c32379a migrations/0002_admin.sql
|
||||||
20112cc82192098b8d602f1c4f7ca08712e9e1366c845fabb92753187c370d35 migrations/0003_certificate_renewals.sql
|
20112cc82192098b8d602f1c4f7ca08712e9e1366c845fabb92753187c370d35 migrations/0003_certificate_renewals.sql
|
||||||
5c62da30fa9db594a4d656c77ae676d3c388072b6a85f91170ec7d911d7cde43 migrations/0004_admin_preferences.sql
|
5c62da30fa9db594a4d656c77ae676d3c388072b6a85f91170ec7d911d7cde43 migrations/0004_admin_preferences.sql
|
||||||
@@ -139,13 +139,13 @@ edb6ee1445b01cd6f3a74a3a607f39fb107d411b49df028d2e0f4679e093de31 scripts/acme_p
|
|||||||
e69813fb1d3a4cdcfb7243964cc323fc21a603087bf2e84188fa42b9d3cee4b5 scripts/acme_rfc2136.py
|
e69813fb1d3a4cdcfb7243964cc323fc21a603087bf2e84188fa42b9d3cee4b5 scripts/acme_rfc2136.py
|
||||||
7e524285bfa2e3dbde0391257660635b039f23b0b3807e9510df663f757a5ad8 scripts/admin_audit.py
|
7e524285bfa2e3dbde0391257660635b039f23b0b3807e9510df663f757a5ad8 scripts/admin_audit.py
|
||||||
20e83f8b6347b819d1d1ea3de5c691c36f0816954a4210b0d3f39557fefe1931 scripts/backup.py
|
20e83f8b6347b819d1d1ea3de5c691c36f0816954a4210b0d3f39557fefe1931 scripts/backup.py
|
||||||
7ec90c877e6c13324f1ea9bba2a8b8d789efcd4180912cb7fa06af4a6fea3a70 scripts/check_source.py
|
d0ca0435b4c3ab5bf62ec80b30f9b3c7d5e618cc39e62fa8c524c47570471d20 scripts/check_source.py
|
||||||
187ee92c8029cdd59e89b4447cf4d170e856017a2091ceb85ae7c22dd1a79c72 scripts/deploy.py
|
187ee92c8029cdd59e89b4447cf4d170e856017a2091ceb85ae7c22dd1a79c72 scripts/deploy.py
|
||||||
028dceb22371cecc4d9b1d2e1ea12947a867a389aaff9fc120c5191bd5fb6ece scripts/deploy_core.py
|
381592aa62cc720b2f4aa559f885013027c5ac63d66c4562e688b753f854e818 scripts/deploy_core.py
|
||||||
f014472588e889488976970dbaa95a8745b6907516aa81a7cca21d0f81eaaad3 scripts/deploy_runtime.py
|
f014472588e889488976970dbaa95a8745b6907516aa81a7cca21d0f81eaaad3 scripts/deploy_runtime.py
|
||||||
ee71ccb9fe38d5af4dd131daba0e3edc2f333ae4582af98fd94a3d2b56598be6 scripts/docs_check.py
|
90bd9eee430f67f75f96b2d25f98cc4efb9f3ae065484d32f975dcf19e6ea9bc scripts/docs_check.py
|
||||||
6facb2d65bfab234f09855097d12da8f72669a38ebceb4b1cbd03ab42b8d2469 scripts/langs_check.py
|
6facb2d65bfab234f09855097d12da8f72669a38ebceb4b1cbd03ab42b8d2469 scripts/langs_check.py
|
||||||
2f846042b98a9148be944fb74a2b023b871ff884693a36847837228613a17679 scripts/memory_contracts.py
|
2e35b7c78887fd56f83ca9017caa168630963a9f47da71dfc53b1a8f9ad436c2 scripts/memory_contracts.py
|
||||||
2cc658faaa610b21b48942c59b955525539ad4503fd60f2a49c7e626a22faaff scripts/migrate_npm.py
|
2cc658faaa610b21b48942c59b955525539ad4503fd60f2a49c7e626a22faaff scripts/migrate_npm.py
|
||||||
a459d95bbb0076f33ade8b273b813308167f9d8d45242b309a2d18320ca0093c scripts/migrate_npm_api.py
|
a459d95bbb0076f33ade8b273b813308167f9d8d45242b309a2d18320ca0093c scripts/migrate_npm_api.py
|
||||||
31ccad3ec3c880119f3b7002f0c6652f8b43634edad8ab3763cb0e4497d0bb1f scripts/migrate_npm_core.py
|
31ccad3ec3c880119f3b7002f0c6652f8b43634edad8ab3763cb0e4497d0bb1f scripts/migrate_npm_core.py
|
||||||
@@ -153,8 +153,8 @@ d1418f8e574a7390fd45a2aa879bdf5720b773162d65e295ab0350506aa5220a scripts/mock_a
|
|||||||
2d3ff92300b09ce9cecbbaaa9309b4d33160fa4b2291c9952b784e8cfb599ab5 scripts/mock_server.py
|
2d3ff92300b09ce9cecbbaaa9309b4d33160fa4b2291c9952b784e8cfb599ab5 scripts/mock_server.py
|
||||||
2d4c859aae5ba357a6d30024c8487ae8f59f01b192711f13f9c2f8fee0f48b50 scripts/os-acme-client/README.md
|
2d4c859aae5ba357a6d30024c8487ae8f59f01b192711f13f9c2f8fee0f48b50 scripts/os-acme-client/README.md
|
||||||
c73b814a42bb4ff703441dbd177ee625055eeb115f9b5bb0c2150aede573a159 scripts/os-acme-client/opnsense-rustproxy-cert-deploy.sh
|
c73b814a42bb4ff703441dbd177ee625055eeb115f9b5bb0c2150aede573a159 scripts/os-acme-client/opnsense-rustproxy-cert-deploy.sh
|
||||||
c7f696782d99e2fc35d3fe5cc4abd406ad043cf0f71aa884648da10a42d4f7ff scripts/preflight.py
|
2e57cd5e40162f019e670e1526dade23892139a069c5db8fe04d20385a7aa315 scripts/preflight.py
|
||||||
3b058247f3a0ee106610eca523e4774d64b4379f09ae08d27ceb03f4e84274f9 scripts/release_smoke.py
|
bcf91eaaf6709709f21936a3040a048bbadc434db569823659731780c9b5dcd2 scripts/release_smoke.py
|
||||||
45be151cd85fc2ef2f1fdc3003ace63381af262e73af8a685ab48cb697cc0de1 scripts/routeros-oci-build/.env.routeros.example
|
45be151cd85fc2ef2f1fdc3003ace63381af262e73af8a685ab48cb697cc0de1 scripts/routeros-oci-build/.env.routeros.example
|
||||||
3b48cff8506e5a6ae7d3876f47721f5de7d63e2e02264a78cf5b6ddd52d9fbc6 scripts/routeros-oci-build/Dockerfile.routeros
|
3b48cff8506e5a6ae7d3876f47721f5de7d63e2e02264a78cf5b6ddd52d9fbc6 scripts/routeros-oci-build/Dockerfile.routeros
|
||||||
7c7a3e51f43b43e1c962a4b0bb591f99c1f06977bf77f23719f7f867dfe7eb8e scripts/routeros-oci-build/Dockerfile.routeros.dockerignore
|
7c7a3e51f43b43e1c962a4b0bb591f99c1f06977bf77f23719f7f867dfe7eb8e scripts/routeros-oci-build/Dockerfile.routeros.dockerignore
|
||||||
@@ -166,32 +166,32 @@ ecfe0bb21a7549225a19b0846bb6de8c99cbfbbf5a706d33cf84db2c7146abed scripts/rust_s
|
|||||||
1c83054336b3508d7ad72cd259f039394682642439877fe69639c0b76be09154 scripts/security_contracts.py
|
1c83054336b3508d7ad72cd259f039394682642439877fe69639c0b76be09154 scripts/security_contracts.py
|
||||||
295b6f2625b1875950ea3eecccd142f49be327afdd00c92641286e6de530ec51 scripts/security_dependency_contracts.py
|
295b6f2625b1875950ea3eecccd142f49be327afdd00c92641286e6de530ec51 scripts/security_dependency_contracts.py
|
||||||
a65010f828194885ffc7f0f733937957f28e6049cd978bec1380a2b8bfbd0113 scripts/source_module_contracts.py
|
a65010f828194885ffc7f0f733937957f28e6049cd978bec1380a2b8bfbd0113 scripts/source_module_contracts.py
|
||||||
d42818a70eeba2ee9f2aa8b887dd0cf7fb8e1bcc52990018fc571454e9474d3a scripts/swagger_assets.py
|
cdde3a77767dd6f9694fa4b6a9c322dabe1b461585bc2cb12ebed8a9afcc1a6c scripts/swagger_assets.py
|
||||||
102b23de19a88a8e60de392fb83aefd3dfb33e90cc97ed1690d9f3d4a33d8866 scripts/test_compression.py
|
102b23de19a88a8e60de392fb83aefd3dfb33e90cc97ed1690d9f3d4a33d8866 scripts/test_compression.py
|
||||||
dc2064e5c1c13b2a1fbc30e8e185ce3ac1e6eba58ab26077fd015ee2d26f7274 scripts/upgrade.py
|
f6630becaaae2ca443817b2e16bb8b4940d5b06ab5eaa19d2db720e6344fa282 scripts/upgrade.py
|
||||||
43db35e7264b0345592172f2d1f6a6e4919fc4cbde2a9ff787acd7fff1d031d6 scripts/web_assets.py
|
43db35e7264b0345592172f2d1f6a6e4919fc4cbde2a9ff787acd7fff1d031d6 scripts/web_assets.py
|
||||||
6695c70fe4e64434afe75269136bffce2c30ecf1e2d4c56b6b88b0bf61aaee76 scripts/web_server_contracts.py
|
0cdbedc07475d5c11f53361db7f8da4f2310594c704fcc214904f7a02ba083f4 scripts/web_server_contracts.py
|
||||||
b8ce3e8fd08865015ce312fae9c0457612af18d6ef4513a6281b9e3212f8d458 scripts/web_service_ui_test.mjs
|
b8ce3e8fd08865015ce312fae9c0457612af18d6ef4513a6281b9e3212f8d458 scripts/web_service_ui_test.mjs
|
||||||
d8e2b51c39252dbb4305512fa9b1ef508ec610968aed316b10514fd160298762 src/acl.rs
|
d8e2b51c39252dbb4305512fa9b1ef508ec610968aed316b10514fd160298762 src/acl.rs
|
||||||
e8ffed9a9f50a467062d0758aec6aefdc8a39615282b2eef73603d08bc33c00a src/acl/tests.rs
|
4e3be1ea1be0a81529c7c9021fb9bb77c24e5044acd54094972745443ad2c26a src/acl/tests.rs
|
||||||
992126cb77249a6a173a71b2e5387f218b987545a04b26bc0340f922b4600ec1 src/acme.rs
|
992126cb77249a6a173a71b2e5387f218b987545a04b26bc0340f922b4600ec1 src/acme.rs
|
||||||
6ac56bf1895c26bb5a514ab2f60099add161a7a4bb42d6411264054f824841a5 src/acme/jobs.rs
|
587097620b2f25ce7c6f59f907b47660184b095e3040c7615e74509a82e7cdd8 src/acme/jobs.rs
|
||||||
5ae0514e93148b43a5b587cd870dcc5563f59a65a680ea0080aea6c09bcea96e src/acme/model.rs
|
dbce5e3d3899e8c3c5dcc353c7ad1d2bf76953abca2a6d9d5ae310d206bb1bb1 src/acme/model.rs
|
||||||
c5334de6c732d76b2bea7bfc17b3ac305a250bbaad31a5420d6a7d7abb200449 src/acme/providers.rs
|
c5334de6c732d76b2bea7bfc17b3ac305a250bbaad31a5420d6a7d7abb200449 src/acme/providers.rs
|
||||||
b9e57db4bd80ef37564dfc533a96897d8a494671d53acea9fb4bf28d23ba370d src/acme/providers/tests.rs
|
b9e57db4bd80ef37564dfc533a96897d8a494671d53acea9fb4bf28d23ba370d src/acme/providers/tests.rs
|
||||||
7acbaf34e7b953b753ab074893e47b5024f0cd756dc4c7a1074067dd936c2e8e src/acme/tests.rs
|
7acbaf34e7b953b753ab074893e47b5024f0cd756dc4c7a1074067dd936c2e8e src/acme/tests.rs
|
||||||
8a07a8c9d845e55ffa47332d4379e8ffdc2cee09b22e6c6396edb8e768b24540 src/admin/access.rs
|
55ef7ceb44c25c7a8ddcbfd5e0d4b647526f9bdcde901ee08db5314e4d055b39 src/admin/access.rs
|
||||||
21e4ae7e72b0c86ba674bc820aabdd201cd62126fdd09ba22cc4b420e38ad300 src/admin/certificates.rs
|
85f00f8157e83a152cc531f4cfecd0b1472ce269be9c8eb1ac17ad0693748b42 src/admin/certificates.rs
|
||||||
4361b93f5202f20907781679f8898e8935f044e88a113b5bf93eedccca0c9d81 src/admin/documentation.rs
|
95d05aa0cef117161d4cd688f154b19aa8a99768273ae1f6a5566a919f97630d src/admin/documentation.rs
|
||||||
67b901485d5858d5b5bf78a6260035db32241531d99481754c3533fdf404facb src/admin/documentation/tests.rs
|
67b901485d5858d5b5bf78a6260035db32241531d99481754c3533fdf404facb src/admin/documentation/tests.rs
|
||||||
cc5c84d8476e2ba11c3a4b1996ca616eb402bb0aea734434ac6e185e1041736e src/admin/logging_api.rs
|
beb8be241e4f1a8cea7b6c4e02b42f0359fb1fff10ab5ce2c70ccd0e63a554b0 src/admin/logging_api.rs
|
||||||
468b6062cb806ef489bc107f69d4725dbf9c08d7e18d15b4482ae0f309c15d2f src/admin/mod.rs
|
468b6062cb806ef489bc107f69d4725dbf9c08d7e18d15b4482ae0f309c15d2f src/admin/mod.rs
|
||||||
630e8faea7ed0d8e2a3524b3c52c6ac2b330ca9a59919959e763d69e03f6f54e src/admin/openapi.json
|
20edad7e3c31deea6ab40bf9bf8e44639118f90319dcd95935fa8620d12cf1a7 src/admin/openapi.json
|
||||||
04ac147a823a1b5510977185fc10b4f5e3fddaa76c00ee73ab5209782dd4d859 src/admin/operations.rs
|
a53309daf118381031122ca70764f7a2f92adc44af3fc91df5f946e6856f76ae src/admin/operations.rs
|
||||||
b4fa393b780b2676b5d72e0f90cd7290292f424b8062d4b5983e722d6ca72c32 src/admin/public.rs
|
b4fa393b780b2676b5d72e0f90cd7290292f424b8062d4b5983e722d6ca72c32 src/admin/public.rs
|
||||||
f77cdb17512797f3ff216bc423db647a9e0d2854b7cf775c6ffb853d5c3b2adb src/admin/router.rs
|
ea95e3d74729d652ce467c626a73e433060a195afa31dba5da1fc7ca935678ea src/admin/router.rs
|
||||||
68685c80f57d8e2b0e1d835368893ddc71a8bb3519933fde99e74f6e64a0a6da src/admin/session.rs
|
2672f363659bda3402b12cfaae0878d62750238f965635c7e16d430642aef312 src/admin/session.rs
|
||||||
b882846a576ab254f84f52c4120b3b19d31b2fabb1745aef1feb2b5ccf6bb92a src/admin/status.rs
|
f7938b202919a49fd2ff86ecdf09efadae12e0ffc0a4246a72a76218db11aa88 src/admin/status.rs
|
||||||
cadd7dca29b9aad8c77c7bc23dd249ea37a15adfa4d636a8ef00273a91ce35dc src/admin/tail.rs
|
cadd7dca29b9aad8c77c7bc23dd249ea37a15adfa4d636a8ef00273a91ce35dc src/admin/tail.rs
|
||||||
9bed1f93a8ef7bea4478b26bc825aacc8825ca70cf26c993fe78ac784aab2526 src/admin/tests.rs
|
9bed1f93a8ef7bea4478b26bc825aacc8825ca70cf26c993fe78ac784aab2526 src/admin/tests.rs
|
||||||
5df98246c46135a176b4b8b705c92fd328719e82eb7342f088256abb976d5ae7 src/admin/tests/part_01.rs
|
5df98246c46135a176b4b8b705c92fd328719e82eb7342f088256abb976d5ae7 src/admin/tests/part_01.rs
|
||||||
@@ -203,12 +203,12 @@ b31d594499d7f8164c14b66dd77971b9985cefd99bd4d3686f9ea26e11e5a59c src/admin/test
|
|||||||
78e7d54d6536cd600dcbe66f0fc06ec109e121dfee1e57f3ca6e61cc6ae04a6a src/admin/web/app/config-history.js
|
78e7d54d6536cd600dcbe66f0fc06ec109e121dfee1e57f3ca6e61cc6ae04a6a src/admin/web/app/config-history.js
|
||||||
22252759b3bbdacf887616d6c06113cc3f690884ffe958e7cfbd28bfb2d6805f src/admin/web/app/core.js
|
22252759b3bbdacf887616d6c06113cc3f690884ffe958e7cfbd28bfb2d6805f src/admin/web/app/core.js
|
||||||
19abc332a1009bcb087fe4ebb58d458739b27480ab50715b03d07fd408302942 src/admin/web/app/runtime.js
|
19abc332a1009bcb087fe4ebb58d458739b27480ab50715b03d07fd408302942 src/admin/web/app/runtime.js
|
||||||
66cfbcd7c23dd5731dbe541351968a58b0869681073857086dea5a4256e5c6ca src/admin/web/app/settings.js
|
6dd5e2de7873c812e331546eee00380ec8529b70b9e7321d6ea14642eba80673 src/admin/web/app/settings.js
|
||||||
d0be71555de13f732fd6ee44438a0110eb08c91e78bbc1aa36a1a84182780210 src/admin/web/cache-panel.js
|
d0be71555de13f732fd6ee44438a0110eb08c91e78bbc1aa36a1a84182780210 src/admin/web/cache-panel.js
|
||||||
50d1ebcbaf4d0b2968da23bb943fc3f67131c5d32df3f61d23ff37aad9da5b81 src/admin/web/demo.html
|
50d1ebcbaf4d0b2968da23bb943fc3f67131c5d32df3f61d23ff37aad9da5b81 src/admin/web/demo.html
|
||||||
3b84a7a08f9f68e2c78fed4523b594c31a251addc5480a69c5f6949908230539 src/admin/web/docker.js
|
3b84a7a08f9f68e2c78fed4523b594c31a251addc5480a69c5f6949908230539 src/admin/web/docker.js
|
||||||
590b49972d65aa37fb8eaa16cce53a93e42bb5b42c379671a23493186c241402 src/admin/web/docs.css
|
d4aef376cb44b2a13174dca1cb9383f64c04b0b93279f4f0b4805e76002548a1 src/admin/web/docs.css
|
||||||
b9491f11cf3bc5351d84bc2809495e6d76a6da0d1e84384ad520a5a6e6cf87d3 src/admin/web/docs.html
|
60a4944a0a24b889296991b8af44b467f776fc85ec3597eb2e2940ef1f6fc713 src/admin/web/docs.html
|
||||||
9a8f19f3298769c2c5589cabc6621d73a05ec9f350c21b33e1257ad506c12aab src/admin/web/docs.js
|
9a8f19f3298769c2c5589cabc6621d73a05ec9f350c21b33e1257ad506c12aab src/admin/web/docs.js
|
||||||
232b766f278ae4424705af351910677fcd7ac9a20bb8320d9a12b763c91219a2 src/admin/web/error_401.html
|
232b766f278ae4424705af351910677fcd7ac9a20bb8320d9a12b763c91219a2 src/admin/web/error_401.html
|
||||||
16293363c7848471d866092fec5e83023df087aa824989e87450cee7b7ca1263 src/admin/web/error_403.html
|
16293363c7848471d866092fec5e83023df087aa824989e87450cee7b7ca1263 src/admin/web/error_403.html
|
||||||
@@ -218,7 +218,7 @@ f7d0955ab18c15e04369204e789f341d2e832f927c1ff20a3b2b9e35e7898f00 src/admin/web/
|
|||||||
e6c4d91d1542d0a5b47bb8736f9539d43a6713df5a473b635519d5b7eac2eb9c src/admin/web/error_504.html
|
e6c4d91d1542d0a5b47bb8736f9539d43a6713df5a473b635519d5b7eac2eb9c src/admin/web/error_504.html
|
||||||
0a5fff35555153f59d4346933030a67b6e1a8768cee7a47cfa2fcf1a2c564f63 src/admin/web/favicon.svg
|
0a5fff35555153f59d4346933030a67b6e1a8768cee7a47cfa2fcf1a2c564f63 src/admin/web/favicon.svg
|
||||||
dee3b113907f77138cdf919efdfb097e45b889cff3893bfc6f02ed998643bbae src/admin/web/host404.js
|
dee3b113907f77138cdf919efdfb097e45b889cff3893bfc6f02ed998643bbae src/admin/web/host404.js
|
||||||
91fcc217e73f85b67b58a7c15ec604bd0f57b5c0ff1df2793f956021cbcaa191 src/admin/web/index.html
|
fa46ced03d335eb1b1e855f51fcbbcdeb52b7bfb955ce78f0e56322978bc895d src/admin/web/index.html
|
||||||
24db88842707f764064657712d3660c6ac129fbfb47d188c0903925cf8244ce5 src/admin/web/integrations.js
|
24db88842707f764064657712d3660c6ac129fbfb47d188c0903925cf8244ce5 src/admin/web/integrations.js
|
||||||
cdab0c11a28deebdf401c0453fbc76b675e9e643722106fb20e812bb9648ccde src/admin/web/login-keys.json
|
cdab0c11a28deebdf401c0453fbc76b675e9e643722106fb20e812bb9648ccde src/admin/web/login-keys.json
|
||||||
a253d202dc9a147f2add34c64e0f35c38fdc7f667f9908933ce5f959b1a92a2e src/admin/web/login.html
|
a253d202dc9a147f2add34c64e0f35c38fdc7f667f9908933ce5f959b1a92a2e src/admin/web/login.html
|
||||||
@@ -227,66 +227,66 @@ e41619e5cb0ba01a3d287748f28eb38bbe7641f9bedade252d286c18e619c400 src/admin/web/
|
|||||||
22318f39f7bb1ae98e65737d3c2ad9e63065b8e94ad59bed560c0e80d3a46949 src/admin/web/redirects.js
|
22318f39f7bb1ae98e65737d3c2ad9e63065b8e94ad59bed560c0e80d3a46949 src/admin/web/redirects.js
|
||||||
668f5162fa9f8bbe2fefce4115644a6469e01aa7defc9c7f760c28afd8e2afc7 src/admin/web/settings.js
|
668f5162fa9f8bbe2fefce4115644a6469e01aa7defc9c7f760c28afd8e2afc7 src/admin/web/settings.js
|
||||||
1a30affd6a717095a1763998a5850a79ae0f86b7b694806f2aba2b880735dd1a src/admin/web/streams.js
|
1a30affd6a717095a1763998a5850a79ae0f86b7b694806f2aba2b880735dd1a src/admin/web/streams.js
|
||||||
55be686f59bdf8a462c18912542874fa94661a4fdc3ff70be9d642db27679fa5 src/admin/web/style.css
|
702848ca4331fc68a53aa7df0622c0ca66f8cbb01abe598418754931dbee4360 src/admin/web/style.css
|
||||||
47e98065281c04b4c185d53df4ed0cb12fabc716e52143e6ae3c3c25db62126a src/admin/web/traffic-panel.js
|
47e98065281c04b4c185d53df4ed0cb12fabc716e52143e6ae3c3c25db62126a src/admin/web/traffic-panel.js
|
||||||
049be02e0f68c3f6702f3bf29be760c4e5bc1199393ed198107c0a264711300d src/admin/web/transform-panel.js
|
d818580e61bbb70da1f758b9231c0667639cd947d875a55adc21dcf9ed1319c2 src/admin/web/transform-panel.js
|
||||||
ac79a0f5471f110850bf5ceaaee9a3903bb92fb2edc10e969d8fda81f66571c0 src/admin/web/vhosts/core.js
|
ac79a0f5471f110850bf5ceaaee9a3903bb92fb2edc10e969d8fda81f66571c0 src/admin/web/vhosts/core.js
|
||||||
eefcd49aa90fb11d603392e230d48505de236e73cbcc124fb42cf897febd7136 src/admin/web/vhosts/editor.js
|
c6fa43f90c7f3783b1dee7413a4d3333cef9f9453e74e3d5c85e7051369465bc src/admin/web/vhosts/editor.js
|
||||||
769383dfc5afa28e01a1e99c9eebcce39fc9457fba0602992f750acab9911236 src/admin/web/vhosts/render.js
|
1457a049cd5d266995462bd9cad1b63530c469ecd4b8b80cc9d1e1b6ab4485ed src/admin/web/vhosts/render.js
|
||||||
0de35a0671f3ac8fed62260d63ae43d04efce4947428ebdb9254cff0295295f9 src/admin/web/web-server.js
|
0de35a0671f3ac8fed62260d63ae43d04efce4947428ebdb9254cff0295295f9 src/admin/web/web-server.js
|
||||||
98c00d99822f9be54fc58afb6d4b577901712effd2c5eddce014312681864625 src/auth/files.rs
|
98c00d99822f9be54fc58afb6d4b577901712effd2c5eddce014312681864625 src/auth/files.rs
|
||||||
b2f948bcc3dbd24952c7b1b02d41d06757f49f0c38a78caf51f8f8a687d8480d src/auth/files/tests.rs
|
b2f948bcc3dbd24952c7b1b02d41d06757f49f0c38a78caf51f8f8a687d8480d src/auth/files/tests.rs
|
||||||
e0b37c58d4c391d8f4fa4b1af38a6b53d5107789584797440afb6ef20a711f3b src/auth/mod.rs
|
97b5a060f24a102bbaa2f406426e985236c0d719b8038db210c25b34fcd8e923 src/auth/mod.rs
|
||||||
1ceb57d97cbff655f185e126d98b8dc7884c7aac865e1f70e3c6d199685c13a7 src/auth/store.rs
|
c96a87e82ff0c1c9ce3d0cd5135903bb53af78d1c4fb6ebfe5fea503bf5644ea src/auth/store.rs
|
||||||
745226cabb007819370fc6aa680995a03a8a13fa057dacfab0fcc21d0c43bbe4 src/auth/tests.rs
|
745226cabb007819370fc6aa680995a03a8a13fa057dacfab0fcc21d0c43bbe4 src/auth/tests.rs
|
||||||
b0efb68dec4b0e8611684457b21044d136882ddb5c529f934061a55d377d9b28 src/backup.rs
|
b0efb68dec4b0e8611684457b21044d136882ddb5c529f934061a55d377d9b28 src/backup.rs
|
||||||
002f8f4ba59684937f7601967b6d88b84c4aed641a13222e50500330917c4916 src/backup/archive.rs
|
96fea1da6ba7803d6d532ae8abe4157bc0329a4236e40c0c21a77ddc520b9f11 src/backup/archive.rs
|
||||||
61b0b50d5ed6b4465b8a38ce10f386d877a6c8961a2ec3813976e1a65a511d12 src/backup/snapshot.rs
|
4d7beea1c3d7c65ee6018d22af6461369754c67475b219d3474a85476cd0b57a src/backup/snapshot.rs
|
||||||
daf0686d97d6f570f061b601e3904e15d1fcfa4c11fba9c50199cbfe0ab8e6a2 src/backup/tests.rs
|
5ea9e176dbd5a212438e19fe8abbb0b35ac1d6e1920cbc9bb1b327e4d1e2dcc8 src/backup/tests.rs
|
||||||
32b9da896fd275256ca749189184aa42e82a2ede7e11332ca221b8c2c9f4181f src/backup/validation.rs
|
c8ee6afde0e463828757a9c2aca25506eb0a7b3b9369f4ec955857ab04b1f9d1 src/backup/validation.rs
|
||||||
426a946b2c9e244f09f6cbc5f9664b8ad0737529a9bb5a3d549d27196a1f8043 src/balance.rs
|
426a946b2c9e244f09f6cbc5f9664b8ad0737529a9bb5a3d549d27196a1f8043 src/balance.rs
|
||||||
6521d493edffd36a68a5753d8c808dd66394243f97fd96984b7cbe60588666f1 src/balance/health.rs
|
3d4b3986f54bed99212063b6d135d40a202d556a3e4d253e24c74be4cb9e8ebc src/balance/health.rs
|
||||||
35d42b26de1757a490e936b907bae6803c51582aaaa6a9209eb61a701dd586d9 src/balance/lease_runtime.rs
|
5fef8187a5ca3d22cc76afc72bac211e502c7cffd230353190277d8b9daff583 src/balance/lease_runtime.rs
|
||||||
6b6993caed810bc3a943c9613b1080abd955bf7543dd672ed4b48c4b4a5095bc src/balance/model.rs
|
91c5cef82ece69765858c22c61feb2fb90f38d292cd5bce7ee4fca8f4cb5cd42 src/balance/model.rs
|
||||||
1a5ac7acd28a3876d13745be4d28758b0616d155494083ee66e96fde07d279e7 src/balance/pool_core.rs
|
b5bb2e5d389fc0290c362af8b28c7d625c836876e308bbdcdd7cffcfee2e5e6d src/balance/pool_core.rs
|
||||||
477132dd381e23f1be197c32ff58a0925f41d3e6aa63fe77c10973cefb2b76f6 src/balance/pool_selection.rs
|
477132dd381e23f1be197c32ff58a0925f41d3e6aa63fe77c10973cefb2b76f6 src/balance/pool_selection.rs
|
||||||
f8667285f4dee1d6b6d6ace09e0b57225ec38048fcffe81d72b105b87aa4762e src/balance/pool_view.rs
|
d3ee9cc9869fd0934d1f00fd86943979bac9251630ccf7a2b07e684c7955967e src/balance/pool_view.rs
|
||||||
7d94d1bd4eb698e0588b822d93e56e3dc5594c46edac4aa9713f148893ebe6d5 src/balance/tests.rs
|
7d94d1bd4eb698e0588b822d93e56e3dc5594c46edac4aa9713f148893ebe6d5 src/balance/tests.rs
|
||||||
745952fdae2a6d0efe988fd8cbf44d7330772c28a972dfce3f78e570edd27ee2 src/balance/tests/part_01.rs
|
7c48afa4289beb37e238d4fbc1d9e6f903e7fe3f05d1d7b2cfbdd9103cbedd89 src/balance/tests/part_01.rs
|
||||||
96eeb18c350763af7eb03e2fc843cbb4362e07fbecffea34c6815f7d3731a64c src/balance/tests/part_02.rs
|
490b38a8b1472dbd9fcb823ec0ed0e92498fb9528b982bcee340c8579e89ae36 src/balance/tests/part_02.rs
|
||||||
ccb3e1988d6ae5825450e894eea896d53ae9fac150d0175ea5e742413e55105a src/basic_auth.rs
|
ccb3e1988d6ae5825450e894eea896d53ae9fac150d0175ea5e742413e55105a src/basic_auth.rs
|
||||||
9a8858b7ff461a4d961ba701ca3ed6eaec15c3f7f05eef8e0e30edc63617605a src/basic_auth/tests.rs
|
9a8858b7ff461a4d961ba701ca3ed6eaec15c3f7f05eef8e0e30edc63617605a src/basic_auth/tests.rs
|
||||||
7def03ace07dc38a4806277d75b6ce673d33ddaaf1c4855fa0a3372be1cf9489 src/cache/cold.rs
|
7def03ace07dc38a4806277d75b6ce673d33ddaaf1c4855fa0a3372be1cf9489 src/cache/cold.rs
|
||||||
006cd727ef4e2515576be61af99c72f989ce29002945ac64a0776ebf8dc447ae src/cache/cold/cleanup.rs
|
a9eeb93519aae2de7a1282296ced91d2eb8307cc966f8fbf6085af0fd21b0ad2 src/cache/cold/cleanup.rs
|
||||||
e091ffb895a6e12017c36dee180341ef9446a12e7447a749ca919a1f638cefd3 src/cache/cold/demotion.rs
|
019e7632e09c6f8202d5d919b293f6eb102e1b339e7043fcdbf6b680e8841aca src/cache/cold/demotion.rs
|
||||||
4680051619a2804f327b98435687edd27533cea96f68ab4a8d2668e86437f77d src/cache/cold/startup.rs
|
5de20afb2ecb865d60ebf6593c1dc5167941e0ef812458e6da3bd48f7fd360dd src/cache/cold/startup.rs
|
||||||
5d20f7342df20a95d1cd0a4283287f5e557212998adc5458a642707f453132e5 src/cache/cold/worker.rs
|
5c132e98bcc3fd40e71e8c9666c78e47bbdf801958737e30e6a16ef34f6e324e src/cache/cold/worker.rs
|
||||||
d51fa4f320be56c572f767617428c3f3838543cb0eeb7d1f8ae791e1a1ce9a71 src/cache/collapse.rs
|
d51fa4f320be56c572f767617428c3f3838543cb0eeb7d1f8ae791e1a1ce9a71 src/cache/collapse.rs
|
||||||
27a35689fef639f1aea00d9f5a86adc981c0c304dc3e28e6da40494dffbb6bfa src/cache/dashboard.rs
|
27a35689fef639f1aea00d9f5a86adc981c0c304dc3e28e6da40494dffbb6bfa src/cache/dashboard.rs
|
||||||
bbd6de8568fea79cc4a11d33b905af75713e609c8f37ec943c82f0d180e66dcc src/cache/fill.rs
|
bbd6de8568fea79cc4a11d33b905af75713e609c8f37ec943c82f0d180e66dcc src/cache/fill.rs
|
||||||
675d18afb53f25c56cba49bbb431fa39ecd9d7bdd192c7b39b0698225de7a2a2 src/cache/invalidation.rs
|
675d18afb53f25c56cba49bbb431fa39ecd9d7bdd192c7b39b0698225de7a2a2 src/cache/invalidation.rs
|
||||||
c32bd2350c6561418b28e4f03bbe9f0e3517523eb5eb24f70a130718775bdf2a src/cache/invalidation/ban.rs
|
c1357a13658e1ed5158084d3a41ba9ea906512774a5863ce9c56cb508d3fa6c8 src/cache/invalidation/ban.rs
|
||||||
b963d75d027f297644d8a928f64b44177e874379af607d1b37aa869b2f21eb80 src/cache/invalidation/invalidate.rs
|
7ed64ac876e3be828401e493f08a8d54f28ea75d2c2ff156987848f9dc6097a9 src/cache/invalidation/invalidate.rs
|
||||||
b74945c7460b76ed7afcb02a45ede09d76f08e0703c47920b9b9d794d4b74980 src/cache/lifecycle.rs
|
b74945c7460b76ed7afcb02a45ede09d76f08e0703c47920b9b9d794d4b74980 src/cache/lifecycle.rs
|
||||||
bd831807ca4720b3a41a6ea1d9a6c0ed2d935225e2dacbd9313be064f2e4a20e src/cache/lookup.rs
|
bd831807ca4720b3a41a6ea1d9a6c0ed2d935225e2dacbd9313be064f2e4a20e src/cache/lookup.rs
|
||||||
5a28cf01e860fa586f7b227877889bd529aab3215095016607b5d6524114b1b3 src/cache/lookup/hot.rs
|
108c8e3adfa0e35a3b4daa2d1e94f69278d4ddadc3b6c4d4d9d751298a23b91d src/cache/lookup/hot.rs
|
||||||
b865fe86aeb9ee798da1b69d3b1c74d9c0c7a29e6793eb6cec85886ceaeca734 src/cache/lookup/insert.rs
|
1779abcee77600c13050a2882f896a5b35625b1ae53737c2554179492ce0e40d src/cache/lookup/insert.rs
|
||||||
8a974f04b36bc507615539d44c4290cff8d690478ca0c8691c72225e8c7929a7 src/cache/lookup/tiered.rs
|
f3e026a3c0e953dca3e5c9def43d864a7706afcd7cbeeaf0f21c059a335b30cc src/cache/lookup/tiered.rs
|
||||||
58c03fde09e5eab40968679793b364f4f1cf5fd832bd79ebcdc92bb23871ad82 src/cache/mod.rs
|
58c03fde09e5eab40968679793b364f4f1cf5fd832bd79ebcdc92bb23871ad82 src/cache/mod.rs
|
||||||
f2ce12806e9572f0ac03277d38d9feafa7ed6a045ef010434e33069271ddd6a1 src/cache/model.rs
|
f2ce12806e9572f0ac03277d38d9feafa7ed6a045ef010434e33069271ddd6a1 src/cache/model.rs
|
||||||
c179e5bd35873985d7060094e0ad61b46f4e9cbafdbacfee3b3e24910e13b974 src/cache/model/cache.rs
|
1fafec16201ff94ed52b00697a5ec53fb87a838f62e82fed157fdbc74cb9156e src/cache/model/cache.rs
|
||||||
d203d38f8792963994b041fac07c780eeb33ede27228289165f5374af11e359c src/cache/model/entry.rs
|
dac97eb28052795b7acbbbab1eaf94e8dc1186b07a7e0c4b7dc522af6de02574 src/cache/model/entry.rs
|
||||||
0c20bdc8429ca192988df047ab01ff3001f834ed728273be124dfc6359d43cc8 src/cache/model/maintenance.rs
|
3dd0a5f2bafab4a67a15e76c544bd123eb564aa33e20defbc9e338ef4507da81 src/cache/model/maintenance.rs
|
||||||
36d471e4b417f1eaffe1fd39bdaa64b6a6aa68faf58b26fe42d6b977f08769d9 src/cache/model/settings.rs
|
36d471e4b417f1eaffe1fd39bdaa64b6a6aa68faf58b26fe42d6b977f08769d9 src/cache/model/settings.rs
|
||||||
29e0cd1c1b05ea836cbe716da1940a0590e120ef63eaaae99ec88eb9d797a9b1 src/cache/model/views.rs
|
55dcc0ad84d6b73689ba43e759d5685c406419c7733e23e78d5b072891ab17d7 src/cache/model/views.rs
|
||||||
e26dce02df9c043329ca164fed215d271781bce8fb03240f528331bf3df6b9d7 src/cache/policy.rs
|
e26dce02df9c043329ca164fed215d271781bce8fb03240f528331bf3df6b9d7 src/cache/policy.rs
|
||||||
ee06af7a6d14bc12e73be5c1bd494426c1735d0bba2a8870a2aea4764ba4270c src/cache/policy/request.rs
|
ee06af7a6d14bc12e73be5c1bd494426c1735d0bba2a8870a2aea4764ba4270c src/cache/policy/request.rs
|
||||||
c46f335cf75b91b728125596242a9682a7ef3dbe86242dde7fc038790984a6e4 src/cache/policy/response.rs
|
c46f335cf75b91b728125596242a9682a7ef3dbe86242dde7fc038790984a6e4 src/cache/policy/response.rs
|
||||||
7e2bcfbb2b57732cdc704d9df7a9298fb80e735e37984431bc936630e41e7f8a src/cache/range.rs
|
7e2bcfbb2b57732cdc704d9df7a9298fb80e735e37984431bc936630e41e7f8a src/cache/range.rs
|
||||||
efde2bd046ed073900cd3e67051f0542c802a06e8f5e38c2c20ee92604080c36 src/cache/tests.rs
|
efde2bd046ed073900cd3e67051f0542c802a06e8f5e38c2c20ee92604080c36 src/cache/tests.rs
|
||||||
13dab7b7a587cfc146826a92ab94ec9e04f7e500b7a84e678d77226829844923 src/cache/tests/cold_tier_tests.rs
|
13dab7b7a587cfc146826a92ab94ec9e04f7e500b7a84e678d77226829844923 src/cache/tests/cold_tier_tests.rs
|
||||||
332297f1bc2164795f501f75a145f56c30fe97c88b37c71ca34f3a4aba503b9c src/cache/tests/cold_tier_tests/part_01.rs
|
b4f609ee900c556b613136bbd3fce11c242a415d277ac3d25bdcb72275b66832 src/cache/tests/cold_tier_tests/part_01.rs
|
||||||
5e4dfdf1878bfe7a859460020f4981f2d4ab995c42b6dd1129ae5791481c64bd src/cache/tests/cold_tier_tests/part_02.rs
|
fb3074fa87b19a66db66842f2ab3a0728646293ca2154ab26f7865a58cda56ac src/cache/tests/cold_tier_tests/part_02.rs
|
||||||
8bcbd6e8158620c4e0c056b2872e0b5f786d5f2bc2e2203351b8416a94641f09 src/cache/tests/dashboard_tests.rs
|
8bcbd6e8158620c4e0c056b2872e0b5f786d5f2bc2e2203351b8416a94641f09 src/cache/tests/dashboard_tests.rs
|
||||||
6c69ef40567d34671d26231358e2db74cc26ec0113843303caa98d4dc0fbf1f9 src/cache/tests/scope_tests.rs
|
6c69ef40567d34671d26231358e2db74cc26ec0113843303caa98d4dc0fbf1f9 src/cache/tests/scope_tests.rs
|
||||||
578b18cac918ba51fad775eca188f645b228500e59eb1790f783a0b8d0245b7b src/cache/tests/tests.rs
|
578b18cac918ba51fad775eca188f645b228500e59eb1790f783a0b8d0245b7b src/cache/tests/tests.rs
|
||||||
@@ -297,21 +297,21 @@ cdc41a7241739b89297494323f29e0230fa06abbd74e219fedfda11df1db4334 src/cache/test
|
|||||||
541a62b749440aa1099cf0fc8a2bd31eac0c082ccef35df22c1e049e7928e216 src/cache/tests/v022_cache_tests.rs
|
541a62b749440aa1099cf0fc8a2bd31eac0c082ccef35df22c1e049e7928e216 src/cache/tests/v022_cache_tests.rs
|
||||||
15e85357c3ddf4fc2283d621f5f4cd8ca309275e06677020299d4105f0475949 src/cache/tests/v022_cache_tests/part_01.rs
|
15e85357c3ddf4fc2283d621f5f4cd8ca309275e06677020299d4105f0475949 src/cache/tests/v022_cache_tests/part_01.rs
|
||||||
7ee652a781081c0b53d39dff213c2bda38e405a18a3d0b908f97cd3ac51d556f src/cache/tests/v022_cache_tests/part_02.rs
|
7ee652a781081c0b53d39dff213c2bda38e405a18a3d0b908f97cd3ac51d556f src/cache/tests/v022_cache_tests/part_02.rs
|
||||||
bc7f52d55c707fbb409306eadd9aa31115e823590f81b24f68a45264a6f6c86e src/cache/tickets.rs
|
f9a3c4f0c7363819a0904860531078df89e2ee1ed5bcff7047986e40c9f38a0c src/cache/tickets.rs
|
||||||
992e62f8240aa462b9c670eea6e46e86391d4eb82402f3278c23ad73acc89b1f src/compression.rs
|
992e62f8240aa462b9c670eea6e46e86391d4eb82402f3278c23ad73acc89b1f src/compression.rs
|
||||||
ad47db6519e471ec53a408129bb10a794033430e28fcd3d9a4cf273669900829 src/compression/tests.rs
|
ad47db6519e471ec53a408129bb10a794033430e28fcd3d9a4cf273669900829 src/compression/tests.rs
|
||||||
7921ae451ccd65d647165b02919bd97399399da471454a6a1a1f63e682b76fc8 src/config.rs
|
7921ae451ccd65d647165b02919bd97399399da471454a6a1a1f63e682b76fc8 src/config.rs
|
||||||
fcb45e7b5cf59f1fd18975db501eafcfb8d70c6139589d851f46a3fc5eac043e src/config/backend.rs
|
36c8774fe6fdc44d13286b7688726ceaa9b55cee4c63113689df63456cbecaac src/config/backend.rs
|
||||||
0ce2c6b96fd96518258f08c8ed73db333948a623796a81f8af0976c3bea1e188 src/config/compile.rs
|
8b39e92594133c32b6e113c67849fc10f51ceec9e3bbf69211779f6628d0e001 src/config/compile.rs
|
||||||
66b3061200c06c4fffe3350e3807bd9948b9b05aa91410da5d05edef1e0d791d src/config/model.rs
|
66b3061200c06c4fffe3350e3807bd9948b9b05aa91410da5d05edef1e0d791d src/config/model.rs
|
||||||
a74c5879d66129f8c32677dec9594281c412b890d09605d380c0e3a61a56db23 src/config/routing.rs
|
4d2a4a078e890a9d1582e2cc6f9b8f0e8c2c676c4c94bc927bffdbe55e932610 src/config/routing.rs
|
||||||
51aa3205dbe5c9a789369736285703338b1524b8fe7cd366eb935abf3dd6bfb9 src/config/snapshot.rs
|
9bc22e19b7cfd3b7555faac8497c7410ef48e8c6b4eb3515f77f6a0e2f251c5d src/config/snapshot.rs
|
||||||
7d94d1bd4eb698e0588b822d93e56e3dc5594c46edac4aa9713f148893ebe6d5 src/config/tests.rs
|
7d94d1bd4eb698e0588b822d93e56e3dc5594c46edac4aa9713f148893ebe6d5 src/config/tests.rs
|
||||||
be6852c11041bcea2c387b76ba3d66a8ac06f8425bd1c976075efe5cc802902d src/config/tests/part_01.rs
|
421501ac3c524b14a5b7f51bdca75acd69903cc45dcbc51bd5e295a29e3e5ba0 src/config/tests/part_01.rs
|
||||||
467b89435d0d115b227c8c8093d06c3443b5c4c063bc18e322e7d2edf635a02e src/config/tests/part_02.rs
|
fb0d4d91ae95fe551b06b9195f9e6d41bc40fb6a3a7c547b170fcfeb9abe213c src/config/tests/part_02.rs
|
||||||
fa4e955ad23c0b5b3fb25af9f144c5c483f116fb79568300543b6501575d9e18 src/db.rs
|
fa4e955ad23c0b5b3fb25af9f144c5c483f116fb79568300543b6501575d9e18 src/db.rs
|
||||||
fe229630e81b10b25edc1319857db1ef406cf5acc4cce4b4cd90f855d1cf55de src/db/history.rs
|
2ff744223934685439374572b83fd639bb3eabdbac168bea4a6501a6e9ce0ee0 src/db/history.rs
|
||||||
49200d4e69ad929d69d249fc3849b4227170e47016599fb034e6858322588753 src/db/tests.rs
|
eb0f3d5ca222d36a915493e9bb96ef34dfe3abc627ec887782f9dda6f3174754 src/db/tests.rs
|
||||||
19ab6c3ae37009c544291cb0b65c1bb9c721e168f95c1ed3fa88155aca7463ad src/demo.rs
|
19ab6c3ae37009c544291cb0b65c1bb9c721e168f95c1ed3fa88155aca7463ad src/demo.rs
|
||||||
e69031875ffec32c9f548c43bed5f1a5c4c626e9568c9173e3b093f9a8b73036 src/diagnostics.rs
|
e69031875ffec32c9f548c43bed5f1a5c4c626e9568c9173e3b093f9a8b73036 src/diagnostics.rs
|
||||||
b45d6040810c93ae2acb04ef6b0a59c189751edf9008cd81a4521c9e04e7f07d src/docker.rs
|
b45d6040810c93ae2acb04ef6b0a59c189751edf9008cd81a4521c9e04e7f07d src/docker.rs
|
||||||
@@ -329,112 +329,114 @@ e40171e72327bc4350ba95cedacde2f3c9148c26a5a232d9f790f4449f20a685 src/geoip/test
|
|||||||
68bc11160bc5275a904e48af8698b37433096fb6d592364d8281d59bb9e2b3f4 src/http3/tests.rs
|
68bc11160bc5275a904e48af8698b37433096fb6d592364d8281d59bb9e2b3f4 src/http3/tests.rs
|
||||||
3dab8fac75263120e48ee869ad55a3e2ccc2a19fc9f6d6a6fe055657ec55b1e3 src/lib.rs
|
3dab8fac75263120e48ee869ad55a3e2ccc2a19fc9f6d6a6fe055657ec55b1e3 src/lib.rs
|
||||||
6946917d57fb589bdba639fef2cec1d256fac0c8bfde92adffef2b31c3b3e08c src/logging.rs
|
6946917d57fb589bdba639fef2cec1d256fac0c8bfde92adffef2b31c3b3e08c src/logging.rs
|
||||||
e77598ade4ad6fc27f384bd1ee42005cd745c31c2306ffe03a94be6fbf97eee2 src/logging/format.rs
|
4ef787e9c180f0ac6ba5781711becd0b08d7517520fc03e21248e442d8fe2901 src/logging/format.rs
|
||||||
345f46b92afdeb554f4459b1c37c14cb63d2d4dfdaff8be7750ce1a80dd451f0 src/logging/model.rs
|
147825d3c6dbb4c794c18897703741aa6b60bbfa3dbae0e30b6f770e2a8672ba src/logging/model.rs
|
||||||
13194c28f0e38e00727c70552403e3f45d4aa819ed0aba168c60d098fc03f232 src/logging/runtime.rs
|
348db1112a6067b06f4620ae75d2fc57d275852fef995b52649a6112b8c6589c src/logging/runtime.rs
|
||||||
8c1f4a05a538daeda2de5a35d073750c910aed808746275afe58cf5a9d2c392d src/logging/tests.rs
|
6a07c1eeb6914b863ba7581444486029ca0c7465d2427f251bd1143cbba49448 src/logging/tests.rs
|
||||||
3836ed14b6710e183f048ee4d7807a35366c27a27338057fe4a2811129b63302 src/main.rs
|
3836ed14b6710e183f048ee4d7807a35366c27a27338057fe4a2811129b63302 src/main.rs
|
||||||
79e1d39d7be966c22faad99146e384407427f2b1cec917b73786c5808ecc12f1 src/main/admin_runtime.rs
|
46732ed6d9cf2a33031624f941b8318d2676fb1b6bb5142e96820301f9fa1ac4 src/main/admin_runtime.rs
|
||||||
7751340e2931390f8464e04e4d8d874936b2620624ae4e52db17cdc2a21c4c09 src/main/bootstrap.rs
|
f31da9bff5455db1c0c793116f2cee209022555b9f3d804ef9f1662a1ae05e83 src/main/bootstrap.rs
|
||||||
192623ac6d9ef376648d3dc372e7dedc0a37afbaa3dacf737e2e372228de09e5 src/main/proxy_runtime.rs
|
5a98d0e249338e73aa57ae2e352dc16db2f79c2d042c1544ce1c2022da76a31c src/main/proxy_runtime.rs
|
||||||
f58e3b75ed39e85fb4f943b970ea5bb271e709bce0979fd96a25e416387a81d9 src/main/shutdown.rs
|
4dd7c1084a6214c0f2513ebf86fe8ef144470695557772bfe25979edd64491ab src/main/shutdown.rs
|
||||||
a8783a34c01a288822c71b2a6807cc8d7645e22af5766053fed5c429d4536407 src/main/shutdown/tests.rs
|
0a6578a0f4023b9f8d73043bf942dc5e096ef9afb8c0d2f131c14f65d08ac01d src/main/shutdown/tests.rs
|
||||||
6f61f3fb5e08bd0786c93ba98e1693edd5bcb2585bda2a6bee4dc9ad415b022e src/main/tasks.rs
|
42784b7f4ff85f942d4dd3cee13a2182c20a0683f0d572eae137305398e7c928 src/main/tasks.rs
|
||||||
49d7e104585c8791ac9a203dddd95802784b68c0ba65d6f90f3d57154b4c7871 src/metrics.rs
|
49d7e104585c8791ac9a203dddd95802784b68c0ba65d6f90f3d57154b4c7871 src/metrics.rs
|
||||||
201ab702722d6d21585fe8bb49939150d61bfac7ed8dc198b98c2cc6098ffb5f src/metrics/global.rs
|
201ab702722d6d21585fe8bb49939150d61bfac7ed8dc198b98c2cc6098ffb5f src/metrics/global.rs
|
||||||
b1ed4042f2d6c1029523c3977b85e2ab6020e2da7d5079f98051cef5e96ca390 src/metrics/vhost.rs
|
49b11df65b4fb0b5b727f9f867436584680b45e3f4fbd53f74bc0cab8b9a88ec src/metrics/vhost.rs
|
||||||
a54b5b34ea65f29723b89b81bf7968a238e8247b9c9760f3430d3504cb1017c9 src/metrics/vhost/tests.rs
|
a54b5b34ea65f29723b89b81bf7968a238e8247b9c9760f3430d3504cb1017c9 src/metrics/vhost/tests.rs
|
||||||
a4702c95c7e5077c2ccff86e2e3216e1da6ff9ee4383ae199a0aff2f78db325f src/not_found.rs
|
a4702c95c7e5077c2ccff86e2e3216e1da6ff9ee4383ae199a0aff2f78db325f src/not_found.rs
|
||||||
5b3c5f28245df529f3099f16fb4fd93c00e760b1202d4b692c1d1d79601f6144 src/not_found/tests.rs
|
668840e7bd70590e2e13f59b6d5b9e43ca7c877f3d07c71907baea91b5bba6cb src/not_found/tests.rs
|
||||||
6aab4f97d72ec6352c940bc89e911b8e50c580821da8202744e9832621458784 src/pages.rs
|
6aab4f97d72ec6352c940bc89e911b8e50c580821da8202744e9832621458784 src/pages.rs
|
||||||
73a0770726eb90f89fe1a65e0e146c39209120e70d5817fe2e8e63f3c3521c40 src/pages/tests.rs
|
73a0770726eb90f89fe1a65e0e146c39209120e70d5817fe2e8e63f3c3521c40 src/pages/tests.rs
|
||||||
4198844bc70c59ca3f8da812928391e2ca3d4eebc84bde432a5724c0c63d414b src/prometheus.rs
|
4198844bc70c59ca3f8da812928391e2ca3d4eebc84bde432a5724c0c63d414b src/prometheus.rs
|
||||||
32456ef4b45b8f57cafda60c636c9f41b1cc37c1050f45839f60e6adaaa4e1ac src/prometheus/core.rs
|
ff1c502ed1ce8d5de9ba7685253a6b70793ca9824b75fba58bae8aa6c4c11b84 src/prometheus/core.rs
|
||||||
000bfc20822a254f0330e595136018991af88529198aa298cbeff83447e421cc src/prometheus/docker_misc.rs
|
5da9771bbd9843febe80cc9a722a9ada9d20cfb8d22addde7fef2c4edb66f327 src/prometheus/docker_misc.rs
|
||||||
1b614f3a258c8c9c3b7818f42cbc75777370261a388b5fd9ef1546acad2bd1f2 src/prometheus/model.rs
|
d3c6b08088df0003144544936a55e2a3661aac85292821b594f00adfd19a2951 src/prometheus/model.rs
|
||||||
c1b30f843149ab3a3c91c9bcb44c691308234696a1c450cb41b4dceedb2c2eb9 src/prometheus/tests.rs
|
064b2be7fed2f6acf526b1cce070c1bb1b943d36f08fa50bbfcbdf3cf1c9318c src/prometheus/tests.rs
|
||||||
f59ff86433d2922704e1982b30a36c4b2e8b067386d5dffa945594b1bdf512da src/prometheus/traffic.rs
|
028e1dd9f2ec2afaf699a6b21c2d4b0d96e76f11f5e4ed009c233dadf0f3be51 src/prometheus/traffic.rs
|
||||||
b3ea198d87f95942a2991c122b4c90e1f0244dd1f592fa276f0df8a43e43ca43 src/prometheus/vhosts_backends.rs
|
cbfb888199cc64c080230a729a00d57c0c56381d50ba45f3ae368e13d761d81f src/prometheus/vhosts_backends.rs
|
||||||
a07b344affed0d464d514a19294822db0d93e241888653752a4d131a94c535d9 src/proxy/body.rs
|
6fc307286ab24b259237d34c6207dd325b375e1e896f824c66c9805a97bb981f src/proxy/body.rs
|
||||||
16b9d4db3b20b2ab14c47ac14fcd18d3d8ca77c3ad9a1f37866ebfa60f379862 src/proxy/body/tests.rs
|
16b9d4db3b20b2ab14c47ac14fcd18d3d8ca77c3ad9a1f37866ebfa60f379862 src/proxy/body/tests.rs
|
||||||
2f04b5530d44827f9fa722ba9f5e80d5f8afdf3af973970afce4a3d540c5fe9c src/proxy/cache_helpers.rs
|
00e50a914511754266b4eae2626244587174bfa71fff91509c530bcde7f0d397 src/proxy/cache_helpers.rs
|
||||||
cfb0910af8cd868bde3f6c9992319e46d5328d6d8f69c50701df0ea12bef2108 src/proxy/forward/cache_lookup.rs
|
cfb0910af8cd868bde3f6c9992319e46d5328d6d8f69c50701df0ea12bef2108 src/proxy/forward/cache_lookup.rs
|
||||||
212de22f407dd96800afcf65fd1fc7c40fede1b88f80d04850eb8d1227b08a5b src/proxy/forward/response.rs
|
212de22f407dd96800afcf65fd1fc7c40fede1b88f80d04850eb8d1227b08a5b src/proxy/forward/response.rs
|
||||||
4bc846cb54bb56577fbbb3c9f3d0c1acd023f4d2b559bb3ed03c6e1e25d93390 src/proxy/forward/route_cache.rs
|
4bc846cb54bb56577fbbb3c9f3d0c1acd023f4d2b559bb3ed03c6e1e25d93390 src/proxy/forward/route_cache.rs
|
||||||
51c620b77004cca26edf387f9650f07d27801e093d32cc0162eaee1d0702c126 src/proxy/forward/success_finish.rs
|
51c620b77004cca26edf387f9650f07d27801e093d32cc0162eaee1d0702c126 src/proxy/forward/success_finish.rs
|
||||||
5b639e63bc0110c93ab166bd22ac5bea5d8fa260e62c41d4bdb25d5ffff129d4 src/proxy/forward/success_prepare.rs
|
5b639e63bc0110c93ab166bd22ac5bea5d8fa260e62c41d4bdb25d5ffff129d4 src/proxy/forward/success_prepare.rs
|
||||||
23b6bd26f6175b52c13d2571318fddd12550ba34ee77b87b5ac0e4811f8e2bee src/proxy/forward/upstream.rs
|
23b6bd26f6175b52c13d2571318fddd12550ba34ee77b87b5ac0e4811f8e2bee src/proxy/forward/upstream.rs
|
||||||
1ae46baf8b0ffab630f9f67977be67215549a5d8c2a57708d28a2d3076c490d0 src/proxy/forward_entry.rs
|
490c8da49d78331750955ac64713ca084fe9ed17597c782d94f9a5986c2b87a0 src/proxy/forward_entry.rs
|
||||||
10d740d2e41c2b1349553f8f6e8d624fda8085f665fe6b4a84d913cd465c5825 src/proxy/headers.rs
|
c438066616527a3108f2ad53e3698ae9b2a80961714394cdd0a450c92f99d992 src/proxy/headers.rs
|
||||||
5cb7522ceb9a9f083a15596ac4898559295e38d1138c80099577211de8a868ec src/proxy/headers/tests.rs
|
5cb7522ceb9a9f083a15596ac4898559295e38d1138c80099577211de8a868ec src/proxy/headers/tests.rs
|
||||||
f6aef54204b5bb9305dd1367818c7ffd3cb273008404c9fab0317af1d13ba7a6 src/proxy/mod.rs
|
f6aef54204b5bb9305dd1367818c7ffd3cb273008404c9fab0317af1d13ba7a6 src/proxy/mod.rs
|
||||||
ac678d8a2c565fc5662d97acf60e3c59850446861103d2fe04719f96295933a8 src/proxy/tests/authority_tests.rs
|
d75ff3e38affa49f9a8b9d6801454c1449458e5fbf07e08d51aa3f42abebafd5 src/proxy/tests/authority_tests.rs
|
||||||
b8214b1c847d80c4d42390e913832e2a393dd35e0c8f0657d6eb8aea3254c155 src/proxy/types.rs
|
622d44511b82883a34830d0ae3ea665fd40b58eaa85653f58588db92d55a17c3 src/proxy/types.rs
|
||||||
e0668cc142d7d0b082371a1e3e78c809bbad8a53fbc2aad62a0dff6138bb8e1e src/proxy/upstream_helpers.rs
|
4ba5a477e6f95d59d5413e6026ba90d1d1b132b0bdf47d344b0a66aab2f9db2a src/proxy/upstream_helpers.rs
|
||||||
69f775f6746b4c6d729dc10961dbef54168846f4ce9cf7fe453ab5a2b879c9b8 src/proxy/websocket.rs
|
69f775f6746b4c6d729dc10961dbef54168846f4ce9cf7fe453ab5a2b879c9b8 src/proxy/websocket.rs
|
||||||
5980ffd2f48248abab72ec96ce22da80a023ccd5e14f6bc21e3c85125876f8b0 src/proxy/websocket/handshake.rs
|
d05e655ba0b3b322c657aaa9c2cbe7a0181064a896026b5eeaca347c4a0b7831 src/proxy/websocket/handshake.rs
|
||||||
11b1d7291c75c5b41aeb551ae87fb4878f93ba68c87178a9aeff88fd84fe2b6a src/proxy/websocket/tests.rs
|
b21dc9cf3817dd4e3273ce25887d63d7a772c477b86ca57f8d5b72b8154456e7 src/proxy/websocket/tests.rs
|
||||||
4aa3d2aae84e7fe6985a5a3adde43ef3a7135e0662c88b11545d4ffb962b738d src/proxy/websocket/tunnel.rs
|
a44421714aab37f7ceda19e3ec2512c645d2a3ce5dcb3da5bc7a0d87a442d6a8 src/proxy/websocket/tunnel.rs
|
||||||
6ae4152d5918b629cfd647ac16f6d33f976d2915e09364c91f66cda746eedcde src/proxy/websocket/validation.rs
|
15fabd38576b61f650c039acdbf7ac5a5bd24330062475b94315285b2dc258b6 src/proxy/websocket/validation.rs
|
||||||
26f57e7e21be5697b57dbeceae8f148c50ac461973adcd8c07a0fd8a8c0d8c33 src/rate_limit.rs
|
26f57e7e21be5697b57dbeceae8f148c50ac461973adcd8c07a0fd8a8c0d8c33 src/rate_limit.rs
|
||||||
3ac0b5c6407b2cf13e28b570ab94aab3ade62faf93e40a06269a058019fde165 src/rate_limit/tests.rs
|
3ac0b5c6407b2cf13e28b570ab94aab3ade62faf93e40a06269a058019fde165 src/rate_limit/tests.rs
|
||||||
d40ad63939097d2b91339127d5835a74b618d83b7ba31db0c512f05a82107d6e src/redirect.rs
|
d40ad63939097d2b91339127d5835a74b618d83b7ba31db0c512f05a82107d6e src/redirect.rs
|
||||||
811c83ae9fd0f5a13d35b5443cd37843f82b9d600bee4bb136ba9b87732a5347 src/redirect/tests.rs
|
811c83ae9fd0f5a13d35b5443cd37843f82b9d600bee4bb136ba9b87732a5347 src/redirect/tests.rs
|
||||||
d0939e1b0829c25356a0b67ecb3a178c74936dd07baa15fee24eb32544db6cad src/runtime.rs
|
d0939e1b0829c25356a0b67ecb3a178c74936dd07baa15fee24eb32544db6cad src/runtime.rs
|
||||||
5e7098a94e18b428e3514acee60d6d5c47b0d7bf01a3a5765184cbe4cdd7fbc1 src/runtime/certificates.rs
|
4e0b25c2b86eefddd76c64b39dc1c1cd6d243addc32cdea99e6c3ac84ed879a6 src/runtime/certificates.rs
|
||||||
117b68f9ae6322eb2037651a2b47de50c5172dbdd12507a07cf7ee4699697b44 src/runtime/constructors.rs
|
117b68f9ae6322eb2037651a2b47de50c5172dbdd12507a07cf7ee4699697b44 src/runtime/constructors.rs
|
||||||
31dc5cdea00efd63594dc6becd5a9103594696145cbc8e7b7594fb407214ad9d src/runtime/docker.rs
|
31dc5cdea00efd63594dc6becd5a9103594696145cbc8e7b7594fb407214ad9d src/runtime/docker.rs
|
||||||
c052b35673d905219a71130b44a5dc0027bf9b853bff0b6bdbed4be4064550ea src/runtime/tests.rs
|
c052b35673d905219a71130b44a5dc0027bf9b853bff0b6bdbed4be4064550ea src/runtime/tests.rs
|
||||||
03144b1b00fb45c5616ca9c9b0e57013e86c1f07f129830aaec98a73b274199f src/runtime/types.rs
|
03144b1b00fb45c5616ca9c9b0e57013e86c1f07f129830aaec98a73b274199f src/runtime/types.rs
|
||||||
8fac75382d2f10e1ce7bf22441d2718cfce779d414f6ac51b390636587091fe0 src/runtime/updates.rs
|
019543a127009acdc2df05a1bbc83b2413c22d056d638a53dbe80636926a546d src/runtime/updates.rs
|
||||||
b4c17b304166592e63c81884076589fbaf725c3f57043f8924c46167b061ac5b src/secret_store.rs
|
b4c17b304166592e63c81884076589fbaf725c3f57043f8924c46167b061ac5b src/secret_store.rs
|
||||||
4a5ab7602324408a436ababc32011c9c8d958987505a05040d9633243ed88ae1 src/secret_store/tests.rs
|
6dca8da072a3bd610704a391bb6e25c9042971f4ebc60edb47665ce1d74cbc58 src/secret_store/tests.rs
|
||||||
6fa1d8c352bce7a16ff0208bc4cdbe80404715df0aff4ed26910a5df57cbbcd4 src/security.rs
|
6fa1d8c352bce7a16ff0208bc4cdbe80404715df0aff4ed26910a5df57cbbcd4 src/security.rs
|
||||||
0e5fc2aff856bf6fd959cba12b5ddd1e3b3cbeb0fbaadde906c811cdfafdaae7 src/security/tests.rs
|
0e5fc2aff856bf6fd959cba12b5ddd1e3b3cbeb0fbaadde906c811cdfafdaae7 src/security/tests.rs
|
||||||
53a4bed4d1233aa434712b946857ea2050acaaf5de011c6dadca5b5c22155a83 src/server.rs
|
53a4bed4d1233aa434712b946857ea2050acaaf5de011c6dadca5b5c22155a83 src/server.rs
|
||||||
2a48d22cdba034f1ba015b657ba7966458b89e411796f286997b728c7101a2d6 src/server/http.rs
|
2a48d22cdba034f1ba015b657ba7966458b89e411796f286997b728c7101a2d6 src/server/http.rs
|
||||||
cdb65a73886c360f453ca8f2ba473baa76e9bad92a36b4b3d350cd5db053577d src/server/listeners.rs
|
8c6ca5eaffb9acab57199d0349722703b903cfff3752baad2cf2596bd51188de src/server/listeners.rs
|
||||||
8838a30cc1b070c7d7deec408b5457e7d0c561f2c583be20bc49d41e7735b316 src/server/serve.rs
|
59f087070279171d7d23a84ba4f5befb617d8bfc34b7fd6493abb037c46b1768 src/server/serve.rs
|
||||||
a51651d9c97965f9c34d127cdd81c14a42532dc26e794165456e80190e29c17b src/server/serve/tests.rs
|
b209c1135aa30c5a2d1edb3f8a80b9b95398b2c2e4c03139b59b8a4955f1eb99 src/server/serve/tests.rs
|
||||||
0ac35c8432c9e3a6d31374e7cd96731b685d9a5e01beb751bdbfff2eb144288b src/server/tls_runtime.rs
|
dfee3f5a4a79dbac5edfd81f4f1a63b4cf26757f604b8b41924ecabcbf37e370 src/server/tls_runtime.rs
|
||||||
1be88858215d393d4f62f04f36a77ee64ce476be1b642c8f37e059c33423fea7 src/settings.rs
|
1be88858215d393d4f62f04f36a77ee64ce476be1b642c8f37e059c33423fea7 src/settings.rs
|
||||||
b8b3150abe1c6f61d3f593e169795aae397b578607710ea6fd887b90f37b872e src/settings/tests.rs
|
b8b3150abe1c6f61d3f593e169795aae397b578607710ea6fd887b90f37b872e src/settings/tests.rs
|
||||||
566daf9c0e1a30da2dc18e51090541a85ced3320a0fc00ed1d1de3e2b4da5072 src/stream.rs
|
566daf9c0e1a30da2dc18e51090541a85ced3320a0fc00ed1d1de3e2b4da5072 src/stream.rs
|
||||||
46d9f63ce13a634e00f38d36ca3bdb217f2e37f04d75a4ef118e7dac9896a489 src/stream/model.rs
|
46d9f63ce13a634e00f38d36ca3bdb217f2e37f04d75a4ef118e7dac9896a489 src/stream/model.rs
|
||||||
9c59bdb856106c0a74d1f8c156b0dd7289a170322ea556bad19bb8de3bf13d69 src/stream/runtime.rs
|
9c59bdb856106c0a74d1f8c156b0dd7289a170322ea556bad19bb8de3bf13d69 src/stream/runtime.rs
|
||||||
71c8850c9f80ec2c2eaa1ab3559670ba6b10be4fa5ad088e94047238d2d0c67b src/stream/tests.rs
|
71c8850c9f80ec2c2eaa1ab3559670ba6b10be4fa5ad088e94047238d2d0c67b src/stream/tests.rs
|
||||||
4767200ef61fd6826471ca7a19b84c43fb1d5dc992dcebeb08f49cdbabaf61f9 src/system_stats/linux.rs
|
ecb12075f5fe78bba9efa1ae89080f7f0ab8dab6c1daa2ac7fd00493f0a3841f src/system_stats/linux.rs
|
||||||
9c29121f17057cbcb3f3ea0a24fe90ad5e6cb80242830290ea55dc66265d8796 src/system_stats/linux/tests.rs
|
9c29121f17057cbcb3f3ea0a24fe90ad5e6cb80242830290ea55dc66265d8796 src/system_stats/linux/tests.rs
|
||||||
182bb00acba5535521d2e056a9bb946e76f672154b92b3649f9fc530c43c363a src/system_stats/mod.rs
|
02701f4a90285dfc32c100f80e421846fbe29f5be935c4268ce3bba42e51e4bd src/system_stats/mod.rs
|
||||||
f5f4d755453ab32196083ab968a42c1210fa9543bc63b29ce7c4653506ecd51a src/system_stats/tests.rs
|
050aa831b1012c4aaade63863f433f01bfacf5d3f95787e57975572116a30ab2 src/system_stats/tests.rs
|
||||||
7467d83066bb6986d8c9103597f7a7617ac677579ed46d573c573ff6ca57bbd9 src/tinyauth.rs
|
7467d83066bb6986d8c9103597f7a7617ac677579ed46d573c573ff6ca57bbd9 src/tinyauth.rs
|
||||||
0e1d87554db55e724f30c41ec4a5c80bdb8fc9c8cba8700ac509864d4abf8871 src/tinyauth/tests.rs
|
0e1d87554db55e724f30c41ec4a5c80bdb8fc9c8cba8700ac509864d4abf8871 src/tinyauth/tests.rs
|
||||||
7d94e9ea622abb2ffee9f2bba43b3d41e603d3e907a42f0fe2a83b0c78faa7b1 src/tls.rs
|
7d94e9ea622abb2ffee9f2bba43b3d41e603d3e907a42f0fe2a83b0c78faa7b1 src/tls.rs
|
||||||
e62b55a057ab39daf540e225342e98a57a6266f1603d685c48468f2f7c37c4b8 src/tls/certificates.rs
|
e62b55a057ab39daf540e225342e98a57a6266f1603d685c48468f2f7c37c4b8 src/tls/certificates.rs
|
||||||
f5af75a2f6b360576393f2fd628144e54c28dbd28cbbc0f9ba59643d12c21c1f src/tls/server_config.rs
|
b094b69eed8fa37fbd00f4cc0ff32a0d72c39c0423e98a352ba7046fc66fc91f src/tls/server_config.rs
|
||||||
4b546ac47c142286e27c729f24df23810e38fc33d02c3b90837663041e55630c src/tls/tests.rs
|
4b546ac47c142286e27c729f24df23810e38fc33d02c3b90837663041e55630c src/tls/tests.rs
|
||||||
e0ab65406911d4b95cb26594df65779a88d9011d5b11adb22c1a28831cda3826 src/tls/tests/acme.rs
|
e0ab65406911d4b95cb26594df65779a88d9011d5b11adb22c1a28831cda3826 src/tls/tests/acme.rs
|
||||||
9196ec11be2f0107bc86c71e302a10868801709c979d07aa9a1119296803c932 src/tls/types.rs
|
9196ec11be2f0107bc86c71e302a10868801709c979d07aa9a1119296803c932 src/tls/types.rs
|
||||||
438506b1743daddcbefe0ebec5a6050d5f9555710446a1578c0a3d326d4b68ac src/traffic.rs
|
438506b1743daddcbefe0ebec5a6050d5f9555710446a1578c0a3d326d4b68ac src/traffic.rs
|
||||||
18d8e9f34255ae7dfd7e7d0d5a8d358a9a6cce5356e9c78db52271b9fea22a7f src/traffic/tests.rs
|
36301bcbd20b557dd3d58e77a9175f3581947f577c0bb0b972899cec6786b03f src/traffic/tests.rs
|
||||||
725eefaab8bd8dcc5a8c92248c72b20860ac49ec3890b618c7cb19c3e4da55e5 src/transform/apply.rs
|
d88c92f5a2a7773bc3e715d24039db35da4df53881f1a0859eec819b96f06d3b src/transform/apply.rs
|
||||||
58178c9fcbe2d6f829c1cbba53a72a7afc0920b4b563b6e0c052f0caa7d27784 src/transform/compile.rs
|
87f8af5261d79072f8215f1fb8a90715a58e7626544fd8176ce840e3111bdb92 src/transform/compile.rs
|
||||||
7005259b77047a8afd8e32f7c1eccac5683cfab9beb2cbf8ae6a4923fc321b6c src/transform/css.rs
|
38dfd1005b1cd9ae21c1e2964a8b464368d8cdff5e525089b3132e0126f211ea src/transform/css.rs
|
||||||
f427ac35285fc486d1c7bef75d7b40c293a969039172961009ceecf540d9f96f src/transform/html.rs
|
5478670cef87777b14a2dab308f5a9182df56d7ea2f5625bdc94aa7e3d661503 src/transform/html.rs
|
||||||
aa99b0d3029ef92c78371cb90e11f2026cce890d1be8e10ebd7fa9bc5cb13287 src/transform/html/tests.rs
|
aa99b0d3029ef92c78371cb90e11f2026cce890d1be8e10ebd7fa9bc5cb13287 src/transform/html/tests.rs
|
||||||
a1d2fec07617c8a8dc425bfaeaf77c844152a0a174568a88a5baf4c317cc6c5c src/transform/js.rs
|
a1d2fec07617c8a8dc425bfaeaf77c844152a0a174568a88a5baf4c317cc6c5c src/transform/js.rs
|
||||||
cf5195ab6bacccae0082da7b3f1bd0382b73fdeb3607f4ae569ca6daab9d10d0 src/transform/js/tests.rs
|
cf5195ab6bacccae0082da7b3f1bd0382b73fdeb3607f4ae569ca6daab9d10d0 src/transform/js/tests.rs
|
||||||
226ae561dc7b0243c04e55e28cdfd2b76acd48cf614d1919b81c196660b03cfb src/transform/json.rs
|
226ae561dc7b0243c04e55e28cdfd2b76acd48cf614d1919b81c196660b03cfb src/transform/json.rs
|
||||||
216e24e29ea87be4a124f95f898e155f127fd959d7d5d9b30f8cd0b2b5018f30 src/transform/json/tests.rs
|
216e24e29ea87be4a124f95f898e155f127fd959d7d5d9b30f8cd0b2b5018f30 src/transform/json/tests.rs
|
||||||
6a8c28be93fb590942493c075b29ace1527981542bd183f232aa82b62e951eca src/transform/mod.rs
|
6a8c28be93fb590942493c075b29ace1527981542bd183f232aa82b62e951eca src/transform/mod.rs
|
||||||
d5cf1c81b9d248376124a09b80e9b67163a6373a1eb6c4142a6a144f4f86eef7 src/transform/model.rs
|
fde2fa3aa94b30d8536afec1c11348cfbd922d0b5ff89e91d34266e8e3863e26 src/transform/model.rs
|
||||||
a4e1d2aa2913587c250f251356431097b76995aee6e8bf9e35c4978a95491de1 src/transform/svg.rs
|
a4e1d2aa2913587c250f251356431097b76995aee6e8bf9e35c4978a95491de1 src/transform/svg.rs
|
||||||
0f53c64f442390ee20a59087a10f8f9ffb58053263e9aa848ddabfae1a6f3f51 src/transform/svg/tests.rs
|
0f53c64f442390ee20a59087a10f8f9ffb58053263e9aa848ddabfae1a6f3f51 src/transform/svg/tests.rs
|
||||||
155d2f2292816061a74eb303469b2f820b3b5f56cc648010e269f9fbe64671dc src/transform/tests.rs
|
76b3cb4ebdba9cbac8e388d3a9d74bd2055db564d8e31869a60e7a439b46f7b3 src/transform/tests.rs
|
||||||
639ed68b2c62a9c8ef23beac480ed4ecb0a7d31672177c9e0bde6c223137fac1 src/update_check.rs
|
639ed68b2c62a9c8ef23beac480ed4ecb0a7d31672177c9e0bde6c223137fac1 src/update_check.rs
|
||||||
b5e505a2c8e38ca5915dd3ea4f0b33a5bf9cc4ef3e0ec20054748bb1820502c3 src/update_check/tests.rs
|
c42d000d1d576721af3ffe930589388693001b8113554a7658f6dcbc665b5d1b src/update_check/tests.rs
|
||||||
e4b85f407103f941cc535116b61527be20e5489af0dfce5371fdfc17bb627844 src/upstream.rs
|
0399f6211c6e33fa12298acc40957f1532ace235c3950c89050a3450ee127299 src/upstream.rs
|
||||||
84bb415eac5d6d7965763681339f2608d2c72aa12c7b7f3ae530ff94740a9223 src/upstream/tests.rs
|
c16b95930f3e5e700961ebc2817c271931b78739707bbfafcb41d67d95a8d19b src/upstream/client.rs
|
||||||
|
aec8868ba0823bc5ea4ab690caff91cc972b333464993d494ced8a949b5ff173 src/upstream/client_tests.rs
|
||||||
|
3a4b097c0d5c0d88fbe881d84bd26a89789f68e4c46ea68b9e4a923dd4977d0b src/upstream/tests.rs
|
||||||
e4c1ff8f53112e7cfad101a266355f7e47b82895480db431662f4cc59a1d9702 src/vhost.rs
|
e4c1ff8f53112e7cfad101a266355f7e47b82895480db431662f4cc59a1d9702 src/vhost.rs
|
||||||
f5bf21d13cb094706ae42c8b5cb760e12b4cf9c71a559c57ac0e1661b40cc17c src/vhost/model.rs
|
f5bf21d13cb094706ae42c8b5cb760e12b4cf9c71a559c57ac0e1661b40cc17c src/vhost/model.rs
|
||||||
7127e081d884863b21c06f700b54884f90ec04efdfce835591b930f2d210faf6 src/vhost/tests.rs
|
7127e081d884863b21c06f700b54884f90ec04efdfce835591b930f2d210faf6 src/vhost/tests.rs
|
||||||
@@ -444,7 +446,7 @@ f0479524d66bfee7a6eed5eea03601630ba82064fb944902deb9166f90fe17cf src/vhost/vali
|
|||||||
9c1c8d6eedecb95eadbfb23c3caea562f6f7a995606ef988f25b58c2d03bcdd5 src/web_server/config/model.rs
|
9c1c8d6eedecb95eadbfb23c3caea562f6f7a995606ef988f25b58c2d03bcdd5 src/web_server/config/model.rs
|
||||||
6191f4d541476c4a3ae296e7dd28bdb9f8a123fc509b47619f6f44519c44d278 src/web_server/config/validation.rs
|
6191f4d541476c4a3ae296e7dd28bdb9f8a123fc509b47619f6f44519c44d278 src/web_server/config/validation.rs
|
||||||
86c744216d7132d8294a6e90ba9be5fd871646006313d1c62506d40c81db9b12 src/web_server/fastcgi.rs
|
86c744216d7132d8294a6e90ba9be5fd871646006313d1c62506d40c81db9b12 src/web_server/fastcgi.rs
|
||||||
a03c662379b52fe31384dde9f76a41e1b982d6232d2fd73c033e18dbd66b6b52 src/web_server/fastcgi/protocol.rs
|
a7039c5e1c9ec46807f26f50effd89fa1c7cb1d0f92e6b8c8f7bc348aa1e7979 src/web_server/fastcgi/protocol.rs
|
||||||
134c4998f6a0aa27e121af1ae3355b7e335488b2ae867ac0a934c58b4eb77191 src/web_server/fastcgi/response.rs
|
134c4998f6a0aa27e121af1ae3355b7e335488b2ae867ac0a934c58b4eb77191 src/web_server/fastcgi/response.rs
|
||||||
8186363315bd998919c6c783e6f7501528f257a5c0da77c5d60f423e8670db5e src/web_server/filesystem.rs
|
8186363315bd998919c6c783e6f7501528f257a5c0da77c5d60f423e8670db5e src/web_server/filesystem.rs
|
||||||
0aafd7f37c4fe784b047646e4ce5ddcb5fe821231a41ed0a9f519529385288a8 src/web_server/htaccess.rs
|
0aafd7f37c4fe784b047646e4ce5ddcb5fe821231a41ed0a9f519529385288a8 src/web_server/htaccess.rs
|
||||||
@@ -454,14 +456,14 @@ a03c662379b52fe31384dde9f76a41e1b982d6232d2fd73c033e18dbd66b6b52 src/web_server
|
|||||||
80f946570c14c8915fd21bfdb1a84dfb6a14c633ab6060acb828fab4c7c21daa src/web_server/mod.rs
|
80f946570c14c8915fd21bfdb1a84dfb6a14c633ab6060acb828fab4c7c21daa src/web_server/mod.rs
|
||||||
67ab8bef567452f123c4b9b46a942b39c93f1f765c128edca7ee808ff1c5e304 src/web_server/request.rs
|
67ab8bef567452f123c4b9b46a942b39c93f1f765c128edca7ee808ff1c5e304 src/web_server/request.rs
|
||||||
c5cb561b0f276e8082f904b9446fa5885f6b3c0608f25ea2ef425061e9f7f6b4 src/web_server/response.rs
|
c5cb561b0f276e8082f904b9446fa5885f6b3c0608f25ea2ef425061e9f7f6b4 src/web_server/response.rs
|
||||||
1ed4b5bfa67f34bcb109df9d21ef75caab931e15c7bc89c642d8c2fd97292b72 src/web_server/response/file.rs
|
622dcb6005b6226709ee407279b72acd41dce7278f49d3f39cc9ae11423d7748 src/web_server/response/file.rs
|
||||||
9aa68251a5f549f4ce3b1bda88d4abb9efc629caf444989381b4117c9488e37b src/web_server/response/headers.rs
|
9aa68251a5f549f4ce3b1bda88d4abb9efc629caf444989381b4117c9488e37b src/web_server/response/headers.rs
|
||||||
2268a6aeed2f565f9791af33e1cd21c56c228c8873b031725b39a6c57184f2d1 src/web_server/routing.rs
|
2268a6aeed2f565f9791af33e1cd21c56c228c8873b031725b39a6c57184f2d1 src/web_server/routing.rs
|
||||||
400e1c8aa2fe857d96036a64499fbc3de44c1e3a53811c5b25101fb843359792 src/web_server/security.rs
|
400e1c8aa2fe857d96036a64499fbc3de44c1e3a53811c5b25101fb843359792 src/web_server/security.rs
|
||||||
3e0b4e92600a7d5abcec92efed532b3a01e0781cb4f2681daac6d6ae13b0a6e9 src/web_server/serve.rs
|
3e0b4e92600a7d5abcec92efed532b3a01e0781cb4f2681daac6d6ae13b0a6e9 src/web_server/serve.rs
|
||||||
cf86c4692080723bbdf8f4105e1abfae33d7fcf020d2ad9e13ebae3943bd0cbe src/web_server/tests.rs
|
cf86c4692080723bbdf8f4105e1abfae33d7fcf020d2ad9e13ebae3943bd0cbe src/web_server/tests.rs
|
||||||
c62752fe2fa6b74ddc9d94d36f8d191376b1575b15d21fc434c5a5da4c932692 src/web_server/tests/part_01.rs
|
c62752fe2fa6b74ddc9d94d36f8d191376b1575b15d21fc434c5a5da4c932692 src/web_server/tests/part_01.rs
|
||||||
b9f6e50669209d68fd69784bbad4b6336b7dc33a8d60c28a241eb57988d8e47f src/web_server/tests/part_02.rs
|
743789497958281203b136057d4bc711b6d1d0c167d2fc1ebbfc5c1d6507a618 src/web_server/tests/part_02.rs
|
||||||
e54f44f6ca1ed2c41e620de9195d32c4f8bb6936c3881745316a07160f87b4fa src/web_server/tests/part_03.rs
|
e54f44f6ca1ed2c41e620de9195d32c4f8bb6936c3881745316a07160f87b4fa src/web_server/tests/part_03.rs
|
||||||
f00743af2cf4a5952caef7a1dcf68e7817b5599a252a9973e1c22045517c0b0e tests/fixtures/argon2id.json
|
f00743af2cf4a5952caef7a1dcf68e7817b5599a252a9973e1c22045517c0b0e tests/fixtures/argon2id.json
|
||||||
1725c10331745dc04a07675784d385260da7b14567b8dba3cbae5e891eb5dadf tests/http2.rs
|
1725c10331745dc04a07675784d385260da7b14567b8dba3cbae5e891eb5dadf tests/http2.rs
|
||||||
|
|||||||
Vendored
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
# Debian packaging
|
# Debian packaging
|
||||||
|
|
||||||
This directory builds the `rustproxy` binary package for RustProxy 0.25.5.
|
This directory builds the `rustproxy` binary package for RustProxy 0.25.6.
|
||||||
The package installs:
|
The package installs:
|
||||||
|
|
||||||
- `/usr/bin/rust-proxy`
|
- `/usr/bin/rust-proxy`
|
||||||
|
|||||||
Vendored
+1
-1
@@ -21,6 +21,6 @@ cargo fetch --locked
|
|||||||
dpkg-buildpackage -us -uc -b
|
dpkg-buildpackage -us -uc -b
|
||||||
|
|
||||||
mkdir -p dist
|
mkdir -p dist
|
||||||
find .. -maxdepth 1 -type f \( -name 'rustproxy_0.25.5_*.deb' -o -name 'rustproxy_0.25.5_*.changes' -o -name 'rustproxy_0.25.5_*.buildinfo' \) \
|
find .. -maxdepth 1 -type f \( -name 'rustproxy_0.25.6_*.deb' -o -name 'rustproxy_0.25.6_*.changes' -o -name 'rustproxy_0.25.6_*.buildinfo' \) \
|
||||||
-exec cp -f {} dist/ \;
|
-exec cp -f {} dist/ \;
|
||||||
echo "Packages copied to $ROOT/dist"
|
echo "Packages copied to $ROOT/dist"
|
||||||
Vendored
+8
@@ -1,3 +1,11 @@
|
|||||||
|
rustproxy (0.25.6) stable; urgency=medium
|
||||||
|
|
||||||
|
* Show upstream client generation, generation requests/age and rotations in the live Backends diagnostics table.
|
||||||
|
* Reuse the existing event/status snapshot path; no extra polling loop or schema migration is added.
|
||||||
|
* Retain the bounded backend-client generation and HTTP/1 buffer defaults from 0.25.5.
|
||||||
|
|
||||||
|
-- RustProxy Maintainers <noreply@example.invalid> Mon, 05 Oct 2026 10:39:00 +0200
|
||||||
|
|
||||||
rustproxy (0.25.5) stable; urgency=medium
|
rustproxy (0.25.5) stable; urgency=medium
|
||||||
|
|
||||||
* Align Revision History modal styling with the shared square-corner dashboard dialogs.
|
* Align Revision History modal styling with the shared square-corner dashboard dialogs.
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ if [[ $# -gt 0 ]]; then shift; fi
|
|||||||
case "$mode" in
|
case "$mode" in
|
||||||
help|-h|--help)
|
help|-h|--help)
|
||||||
cat <<'HELP'
|
cat <<'HELP'
|
||||||
RustProxy 0.25.5
|
RustProxy 0.25.6
|
||||||
./dev.sh Build and start proxy + local panel
|
./dev.sh Build and start proxy + local panel
|
||||||
./dev.sh run [serve flags] Same, with extra server options
|
./dev.sh run [serve flags] Same, with extra server options
|
||||||
./dev.sh admin setup-token Generate/print a one-time setup capability before first login
|
./dev.sh admin setup-token Generate/print a one-time setup capability before first login
|
||||||
@@ -139,7 +139,7 @@ if [[ "$mode" == "test" ]]; then
|
|||||||
printf 'Checking all Rust targets before tests...\n' >&2
|
printf 'Checking all Rust targets before tests...\n' >&2
|
||||||
cargo check --locked --all-targets
|
cargo check --locked --all-targets
|
||||||
fi
|
fi
|
||||||
printf 'Building RustProxy 0.25.5...\n' >&2
|
printf 'Building RustProxy 0.25.6...\n' >&2
|
||||||
cargo build --locked
|
cargo build --locked
|
||||||
BIN="$CARGO_TARGET_DIR/debug/rust-proxy"
|
BIN="$CARGO_TARGET_DIR/debug/rust-proxy"
|
||||||
case "$mode" in
|
case "$mode" in
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
const version = "0.25.5"
|
const version = "0.25.6"
|
||||||
|
|
||||||
type config struct {
|
type config struct {
|
||||||
Listen string
|
Listen string
|
||||||
|
|||||||
+2
-2
@@ -226,8 +226,8 @@ endpoint or separate unsynchronized frontend/backend write API.
|
|||||||
includes `id`, `algorithm`, `ready`, `health_mode`, `sticky_mode`, `keepalive`,
|
includes `id`, `algorithm`, `ready`, `health_mode`, `sticky_mode`, `keepalive`,
|
||||||
`members`. Members expose ID/origin/weight, status, healthy flag, active exchanges,
|
`members`. Members expose ID/origin/weight, status, healthy flag, active exchanges,
|
||||||
request/error/byte totals, EWMA byte rate/header latency, last check/result, failure
|
request/error/byte totals, EWMA byte rate/header latency, last check/result, failure
|
||||||
and success counters, transition count and last upstream status. It does not expose
|
and success counters, transition count, last upstream status and upstream-client
|
||||||
affinity tokens. Member status is up/down/checking/draining/disabled. In health-off
|
generation/request/age/rotation counters. It does not expose affinity tokens. Member status is up/down/checking/draining/disabled. In health-off
|
||||||
mode, eligibility is not proof that the origin is live. Draining describes operator
|
mode, eligibility is not proof that the origin is live. Draining describes operator
|
||||||
intent; inspect `healthy` as well. `ready` reflects new-assignment availability;
|
intent; inspect `healthy` as well. `ready` reflects new-assignment availability;
|
||||||
a pool containing only draining members may still serve existing cookie sessions.
|
a pool containing only draining members may still serve existing cookie sessions.
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
# Administration API access - 0.25.5
|
# Administration API access - 0.25.6
|
||||||
|
|
||||||
## Sign-in boundary
|
## Sign-in boundary
|
||||||
|
|
||||||
|
|||||||
@@ -167,7 +167,7 @@ The 0.25.0 development runtime adds two maintenance mechanisms that do not reloa
|
|||||||
- every 60 seconds on Linux/glibc, RustProxy calls `malloc_trim(0)` from a blocking maintenance task; this can return allocator pages that are already free, but cannot and does not evict live Rust objects;
|
- every 60 seconds on Linux/glibc, RustProxy calls `malloc_trim(0)` from a blocking maintenance task; this can return allocator pages that are already free, but cannot and does not evict live Rust objects;
|
||||||
- HOT cache maintenance trims only least-recently-used entries that have been idle for the configured delay and only while HOT allocation is above the configured target waterline. The pass is bounded by `hot_eviction_max_objects`; recent/active entries are not purged.
|
- HOT cache maintenance trims only least-recently-used entries that have been idle for the configured delay and only while HOT allocation is above the configured target waterline. The pass is bounded by `hot_eviction_max_objects`; recent/active entries are not purged.
|
||||||
|
|
||||||
Upstream HTTP keep-alive is not reset on a timer. It is already bounded per backend by `max_idle_per_host` and `idle_timeout_seconds`, so forcing periodic client/snapshot replacement would trade memory symptoms for connection churn and lower proxy efficiency. If RSS remains high while HOT/transient usage and connection-pool bounds are stable, the remaining resident pages may still be active runtime/TLS/QUIC/Hyper/Tokio working set rather than reclaimable cache memory.
|
Upstream HTTP clients now also have bounded generations. Each backend Hyper client is recycled after 25,000 requests or 3,600 seconds by default (both limits are configurable under vhost keepalive and either can be disabled with `0`). Recycling replaces only the backend client/pool and leaves the vhost snapshot, HOT cache and configuration untouched. HTTP/1 upstream read buffers are capped at 128 KiB by default. This bounds long-lived Hyper/TLS/pool high-water allocations while preserving normal keep-alive reuse inside each generation. The existing 60-second allocator trim can then return already-free glibc pages to the OS.
|
||||||
|
|
||||||
## Hot and cold tiers
|
## Hot and cold tiers
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
# Installing and updating RustProxy 0.25.5
|
# Installing and updating RustProxy 0.25.6
|
||||||
|
|
||||||
The scripts prepare a Linux/systemd installation. This source archive is **not a
|
The scripts prepare a Linux/systemd installation. This source archive is **not a
|
||||||
verified production build**: Rust/Cargo, real CA operations, live systemd startup
|
verified production build**: Rust/Cargo, real CA operations, live systemd startup
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
# Deployment and configuration migration history
|
# Deployment and configuration migration history
|
||||||
|
|
||||||
|
## 0.25.5 -> 0.25.6
|
||||||
|
|
||||||
|
There is no SQLite schema or saved-configuration migration. Version 0.25.6 adds the already-exposed upstream client generation/rotation diagnostics to the live Backends table and keeps the 0.25.5 backend client recycling defaults unchanged.
|
||||||
|
|
||||||
## 0.25.4 -> 0.25.5
|
## 0.25.4 -> 0.25.5
|
||||||
|
|
||||||
There is no SQLite schema or saved-configuration migration. Existing `cloudflare_client_ip` vhost settings remain opt-in. When enabled and the direct peer is a verified Cloudflare edge, RustProxy now prefers a valid `CF-IPCountry` value for country analytics/logging and country policy evaluation, falling back to the installed GeoIP database when that header is unavailable or invalid.
|
There is no SQLite schema or saved-configuration migration. Existing `cloudflare_client_ip` vhost settings remain opt-in. When enabled and the direct peer is a verified Cloudflare edge, RustProxy now prefers a valid `CF-IPCountry` value for country analytics/logging and country policy evaluation, falling back to the installed GeoIP database when that header is unavailable or invalid.
|
||||||
|
|||||||
+30
-23
@@ -1,8 +1,8 @@
|
|||||||
# Verification report - RustProxy 0.25.5
|
# Verification report - RustProxy 0.25.6
|
||||||
|
|
||||||
## Scope
|
## Scope
|
||||||
|
|
||||||
RustProxy 0.25.5 is a patch release for dashboard consistency and observability: Revision History used a separate rounded modal style, Cloudflare-backed vhosts resolved Traffic country from local GeoIP without consulting Cloudflare's verified country header, Prometheus did not expose the bounded Traffic dimensions or an explicit built-in Web Server serving-source view, the mobile dashboard rendered the full section list permanently across the top of the page, and the dashboard lacked a compact About surface. The top bar now exposes project About information and uses the full Documentation label. The patch keeps SQLite schema 8 and the existing configuration format.
|
RustProxy 0.25.6 is a patch release that keeps the bounded upstream-client memory controls from 0.25.5 and makes their runtime state visible in the main Backends diagnostics table. Each row now shows client generation, requests in the current generation, generation age and total rotations. Those values come from the same backend-pool status object delivered through `/api/events` and `/api/status`, so the dashboard refreshes them with the existing live diagnostics path. The defaults remain 25,000 requests, 3,600 seconds and a 131,072-byte upstream HTTP/1 adaptive read-buffer ceiling. Recycling remains local to the backend client and does not reload the vhost or purge cache. SQLite remains schema 8 and no saved-configuration migration is introduced.
|
||||||
|
|
||||||
## Source contracts reviewed
|
## Source contracts reviewed
|
||||||
|
|
||||||
@@ -46,7 +46,8 @@ RustProxy 0.25.5 is a patch release for dashboard consistency and observability:
|
|||||||
- Logging settings are split into Outputs, JSON format and Error log sub-tabs inside one card, matching the Cache subsection layout. `route`, `cache_effective_enabled` and `transform_effective_enabled` are accepted by the same backend validator that saves custom JSON mappings, and the regression test validates then renders those fields.
|
- Logging settings are split into Outputs, JSON format and Error log sub-tabs inside one card, matching the Cache subsection layout. `route`, `cache_effective_enabled` and `transform_effective_enabled` are accepted by the same backend validator that saves custom JSON mappings, and the regression test validates then renders those fields.
|
||||||
- Structured logging exposes `user_agent` and `country`. User-Agent capture defaults on; country capture defaults off. Country resolution is skipped unless capture or an existing country ACL/rate-limit needs it; verified Cloudflare mode prefers trusted `CF-IPCountry`, otherwise local GeoIP is used.
|
- Structured logging exposes `user_agent` and `country`. User-Agent capture defaults on; country capture defaults off. Country resolution is skipped unless capture or an existing country ACL/rate-limit needs it; verified Cloudflare mode prefers trusted `CF-IPCountry`, otherwise local GeoIP is used.
|
||||||
- The authenticated Traffic workspace uses a bounded 2048-sample non-blocking queue, at most 64 vhost buckets and 32-entry approximate top tables for countries, User-Agents, effective client IPs, paths, routes, methods, status classes and cache outcomes. It never writes per-request analytics to SQLite. The Traffic UI is split into Overview, Clients, Requests and Delivery sub-tabs. Countries/methods/status/cache use donut summaries; User-Agent, effective client IP, path, route and request/response byte volume use bounded horizontal bar charts from the same in-memory TOP state.
|
- The authenticated Traffic workspace uses a bounded 2048-sample non-blocking queue, at most 64 vhost buckets and 32-entry approximate top tables for countries, User-Agents, effective client IPs, paths, routes, methods, status classes and cache outcomes. It never writes per-request analytics to SQLite. The Traffic UI is split into Overview, Clients, Requests and Delivery sub-tabs. Countries/methods/status/cache use donut summaries; User-Agent, effective client IP, path, route and request/response byte volume use bounded horizontal bar charts from the same in-memory TOP state.
|
||||||
- Sustained-traffic memory maintenance calls `malloc_trim(0)` every 60 seconds on Linux/glibc to release already-free allocator pages and trims HOT objects only when above the configured waterline and idle past the configured age. It does not periodically reload vhosts, purge active objects or reset bounded upstream keep-alive pools.
|
- Sustained-traffic memory maintenance calls `malloc_trim(0)` every 60 seconds on Linux/glibc to release already-free allocator pages and trims HOT objects only when above the configured waterline and idle past the configured age. Backend Hyper clients additionally recycle their connection-pool generation after 25,000 requests or 3,600 seconds by default; both triggers are configurable/disableable per vhost, and HTTP/1 upstream adaptive read buffers default to a 128 KiB ceiling. Recycling does not publish a new vhost snapshot or purge cache.
|
||||||
|
- The live Backends table renders `upstream_client_generation`, `upstream_client_generation_requests`, `upstream_client_generation_age_seconds` and `upstream_client_rotations_total` in the same row as Active/Requests/Errors/Latency/Traffic. `app/core.js` feeds the table from the existing `/api/events` `snapshot.status` payload, so the new fields do not introduce another polling loop or control-plane query.
|
||||||
- Cache compatibility currently includes vhost configuration, so a cache-affecting vhost save can purge cache during snapshot publication; replacing the compiled snapshot also retires its upstream clients after outstanding references drain. These mechanisms explain why a manual vhost save can visibly reduce RSS without implying that reloads are required for steady-state operation.
|
- Cache compatibility currently includes vhost configuration, so a cache-affecting vhost save can purge cache during snapshot publication; replacing the compiled snapshot also retires its upstream clients after outstanding references drain. These mechanisms explain why a manual vhost save can visibly reduce RSS without implying that reloads are required for steady-state operation.
|
||||||
- The Web Server list now uses the same vhost card/detail-cell visual structure as the Vhosts list. Reverse Proxy vhost creation reports a dedicated “at least one backend” validation error instead of the generic paths/ACL/headers JSON error.
|
- The Web Server list now uses the same vhost card/detail-cell visual structure as the Vhosts list. Reverse Proxy vhost creation reports a dedicated “at least one backend” validation error instead of the generic paths/ACL/headers JSON error.
|
||||||
- Web Service cards use only the shared `el(...)` DOM helper; a regression contract rejects the previous undefined `text(...)` call that aborted list rendering. Authenticated-shell startup now verifies `/api/auth/session` first and never reveals the legacy embedded sign-in form for non-authentication JavaScript/API failures, preventing F5 from falsely presenting the user as logged out.
|
- Web Service cards use only the shared `el(...)` DOM helper; a regression contract rejects the previous undefined `text(...)` call that aborted list rendering. Authenticated-shell startup now verifies `/api/auth/session` first and never reveals the legacy embedded sign-in form for non-authentication JavaScript/API failures, preventing F5 from falsely presenting the user as logged out.
|
||||||
@@ -58,41 +59,47 @@ RustProxy 0.25.5 is a patch release for dashboard consistency and observability:
|
|||||||
|
|
||||||
## Implemented automated coverage
|
## Implemented automated coverage
|
||||||
|
|
||||||
Rust unit tests in `src/web_server/tests.rs` cover GET/HEAD/index/slash redirect, MIME/length, validators, valid/invalid range handling, If-Range, escaped/repeated directory listings, per-directory index-before-listing fallback, generic 403/HEAD behavior, MIME overrides/default MIME, cache rules, source headers, `try_files`, rewrite redirect/internal behavior, `.htaccess` WordPress-style front-controller routing, nested DirectoryIndex/MIME/Header/Expires behavior, strict-mode rejection and PHP-source protection, hardening probe/method blocking and fingerprint-header stripping, precompressed representations/ranges, download headers, PHP FastCGI fixture execution/failure-source-disclosure behavior, request-body 413 enforcement, custom FastCGI/PHP_VALUE validation and reserved-parameter rejection, direct traversal rejection and Unix/Linux symlink policy. `src/traffic/tests.rs` includes bounded-table, effective-client-IP view and fixed Prometheus User-Agent/method family coverage. Configuration tests cover pure static vhosts without a pool, mixed Web Server/Reverse Proxy routing, reuse of one Web Service by multiple vhosts, unknown service references and backward-compatible default source behavior. Vhost tests cover method-policy normalization/allow/block behavior, database tests cover retained configuration revision documents, actor metadata and previous-revision lookup, and admin tests cover restoring revision 1 as revision 3 while preserving the previous document and emitting `config.restore`. ACL tests include encoded traversal/separator/malformed-encoding cases.
|
Rust unit tests in `src/web_server/tests.rs` cover GET/HEAD/index/slash redirect, MIME/length, validators, valid/invalid range handling, If-Range, escaped/repeated directory listings, per-directory index-before-listing fallback, generic 403/HEAD behavior, MIME overrides/default MIME, cache rules, source headers, `try_files`, rewrite redirect/internal behavior, `.htaccess` WordPress-style front-controller routing, nested DirectoryIndex/MIME/Header/Expires behavior, strict-mode rejection and PHP-source protection, hardening probe/method blocking and fingerprint-header stripping, precompressed representations/ranges, download headers, PHP FastCGI fixture execution/failure-source-disclosure behavior, request-body 413 enforcement, custom FastCGI/PHP_VALUE validation and reserved-parameter rejection, direct traversal rejection and Unix/Linux symlink policy. Upstream tests cover request-budget client generation recycling and disabled recycling; balancing tests cover the new keepalive defaults and validation bounds. `src/traffic/tests.rs` includes bounded-table, effective-client-IP view and fixed Prometheus User-Agent/method family coverage. Configuration tests cover pure static vhosts without a pool, mixed Web Server/Reverse Proxy routing, reuse of one Web Service by multiple vhosts, unknown service references and backward-compatible default source behavior. Vhost tests cover method-policy normalization/allow/block behavior, database tests cover retained configuration revision documents, actor metadata and previous-revision lookup, and admin tests cover restoring revision 1 as revision 3 while preserving the previous document and emitting `config.restore`. ACL tests include encoded traversal/separator/malformed-encoding cases.
|
||||||
|
|
||||||
Rust-independent release checks additionally validate UI/JSON/language/source contracts and reproducible packaging.
|
Rust-independent release checks additionally validate UI/JSON/language/source contracts and reproducible packaging.
|
||||||
|
|
||||||
During the prior 0.25.4 compiler gate, an external build exposed one module-privacy error in the history split (`CONFIG_HISTORY_CAPACITY` was private to `db::history`) and one unused `country_resolved` assignment in the location GeoIP branch. Both were corrected before the 0.25.5 baseline: the capacity is exposed to its parent module with `pub(super)`, referenced through `history::CONFIG_HISTORY_CAPACITY`, and the dead assignment is removed. This workspace still has no Rust/Cargo toolchain, so compiler confirmation of the 0.25.5 tree remains a release-host gate.
|
During the prior 0.25.4 compiler gate, an external build exposed one module-privacy error in the history split (`CONFIG_HISTORY_CAPACITY` was private to `db::history`) and one unused `country_resolved` assignment in the location GeoIP branch. Both were corrected before the 0.25.5 baseline: the capacity is exposed to its parent module with `pub(super)`, referenced through `history::CONFIG_HISTORY_CAPACITY`, and the dead assignment is removed. This workspace still has no Rust/Cargo toolchain, so compiler confirmation of the 0.25.6 tree remains a release-host gate.
|
||||||
|
|
||||||
### Modular source-tree verification
|
### Modular source-tree verification
|
||||||
|
|
||||||
- `python3 scripts/rust_module_contracts.py`: PASS. Every repository `.rs` file is at most 500 lines.
|
- The new upstream client implementation is split into `src/upstream/client.rs` with test bodies in `src/upstream/client_tests.rs`; both stay below the 500-line module limit, and `src/upstream.rs` remains below that limit after moving client construction out.
|
||||||
- `python3 scripts/source_module_contracts.py`: PASS. Dashboard JavaScript, Docker Agent Go implementation and operational deploy/NPM-migration Python modules are at most 500 lines; Docker tests remain in `_test.go`, and browser split boundaries/public bundles parse with Node when available.
|
- `python3 scripts/source_module_contracts.py`: PASS. Dashboard JavaScript, Docker Agent Go implementation and operational deploy/NPM-migration Python modules remain within their source-size contracts.
|
||||||
- Oversized `app.js`/`vhosts.js` source is split while the public `/assets/app.js` and `/assets/vhosts.js` URLs remain stable; the Docker Agent is split into model/Docker/network/certificate/server/entry-point files.
|
- `python3 scripts/rust_module_contracts.py` is BLOCKED by a pre-existing source-tree issue in the supplied 0.25.5 baseline archive: `src/admin/documentation.rs` is 554 lines while the contract limit is 500. The same failure reproduces on the unmodified 0.25.5 baseline archive.
|
||||||
- Rust unit-test bodies are isolated under `tests.rs` / `tests/`; implementation files contain only guarded test includes/declarations.
|
- `python3 scripts/docs_check.py` is also BLOCKED by a pre-existing supplied-archive issue: the Reader does not embed `docs/ACME_PROVIDERS.md`. This also reproduces on the unmodified input archive.
|
||||||
- All `include!("*.rs")` targets resolve, split fragments have balanced delimiters, and no fragment ends in a dangling Rust attribute or doc comment.
|
- Rust unit-test bodies added for this change are isolated in a test include file; the implementation module contains only the guarded include declaration.
|
||||||
- Regression guards cover the Web Server split errors previously observed around `#[derive]`, `htaccess`, `server_protocol` and `anyhow::Context`.
|
- Cargo parsing/type checking remains a release-host requirement because this workspace has no Rust toolchain.
|
||||||
- This is a compiler-independent structural check; Cargo parsing/type checking remains a release-host requirement when the Rust toolchain is unavailable in the packaging environment.
|
|
||||||
|
|
||||||
## Verification status in this workspace
|
## Verification status in this workspace
|
||||||
|
|
||||||
| Check | Status |
|
| Check | Status |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `python3 scripts/langs_check.py` | PASS |
|
| `python3 scripts/langs_check.py` | PASS |
|
||||||
| `python3 scripts/docs_check.py` | PASS |
|
| `node --check src/admin/web/vhosts/render.js` | PASS |
|
||||||
| `python3 scripts/memory_contracts.py` | PASS |
|
| Backend live-table source contract | PASS: four client-generation diagnostics are rendered from backend member status fields |
|
||||||
|
| `python3 scripts/memory_contracts.py` | PASS, including upstream generation-recycle/buffer-cap source contracts |
|
||||||
| `python3 scripts/web_server_contracts.py` | PASS |
|
| `python3 scripts/web_server_contracts.py` | PASS |
|
||||||
| Browser JavaScript `node --check` | PASS for split app source, vhost split boundaries/public bundle, Settings, Docs Reader, Web Server and Traffic |
|
| `python3 scripts/security_contracts.py` | PASS |
|
||||||
|
| `python3 scripts/security_dependency_contracts.py` | PASS |
|
||||||
|
| `python3 scripts/source_module_contracts.py` | PASS |
|
||||||
|
| `node --check src/admin/web/vhosts/editor.js` | PASS |
|
||||||
|
| `node scripts/web_service_ui_test.mjs` | PASS |
|
||||||
| OpenAPI/language JSON parse | PASS |
|
| OpenAPI/language JSON parse | PASS |
|
||||||
| Shell `bash -n` | PASS in source/release checks |
|
|
||||||
| `go test ./...` in `docker-agent` | PASS |
|
| `go test ./...` in `docker-agent` | PASS |
|
||||||
| Python source parsing/contract checks | PASS |
|
| SQL migration/backup smoke (`release_smoke.sql_and_backup_smoke`) | PASS |
|
||||||
| `python3 scripts/check_source.py` | PASS |
|
| Stopped-source upgrade smoke (`release_smoke.upgrade_smoke`) | PASS |
|
||||||
| `python3 scripts/release_smoke.py` | PASS |
|
| `python3 scripts/rust_module_contracts.py` | BLOCKED by pre-existing `src/admin/documentation.rs` 554-line baseline failure |
|
||||||
| `./dev.sh test` Rust-independent phases | PASS; Rust phase BLOCKED because Cargo is unavailable |
|
| `python3 scripts/docs_check.py` | BLOCKED by pre-existing missing `docs/ACME_PROVIDERS.md` Reader embed |
|
||||||
|
| `python3 scripts/check_source.py` | BLOCKED because it invokes the same pre-existing Rust module-size gate |
|
||||||
|
| `python3 scripts/release_smoke.py` | BLOCKED because it invokes the same pre-existing Rust module-size gate; its SQL/upgrade smoke functions pass when run directly |
|
||||||
|
| `./dev.sh test` | BLOCKED at the same pre-existing Rust module-size gate before reaching Cargo |
|
||||||
| `cargo fmt --all` / `./dev.sh fmt` | BLOCKED: Rust/Cargo toolchain unavailable in this workspace |
|
| `cargo fmt --all` / `./dev.sh fmt` | BLOCKED: Rust/Cargo toolchain unavailable in this workspace |
|
||||||
| `cargo check --locked --all-targets` / `./dev.sh check` | BLOCKED: Rust/Cargo toolchain unavailable in this workspace |
|
| `cargo check --locked --all-targets` / `./dev.sh check` | BLOCKED: Rust/Cargo toolchain unavailable in this workspace |
|
||||||
| `cargo test --locked --all-targets` / Rust phase of `./dev.sh test` | BLOCKED: Rust/Cargo toolchain unavailable in this workspace |
|
| `cargo test --locked --all-targets` | BLOCKED: Rust/Cargo toolchain unavailable in this workspace |
|
||||||
| Live H1/H2/H3 Web Server integration and large-file acceptance | release-host acceptance gate |
|
| Live sustained HTTPS/HTTP/1.1 RSS acceptance | release-host acceptance gate; verify RSS plateau and `upstream_client_rotations_total` under representative traffic |
|
||||||
|
|
||||||
The source package therefore has static/source-contract verification here, but compiler-enabled and live transport acceptance must still be run on the release host before production release.
|
The new source-level memory bounds and UI/config contracts pass the available targeted checks. Compiler-enabled and sustained-traffic runtime acceptance remain required before production release; two unrelated static gates are already failing in the supplied 0.25.5 baseline as described above.
|
||||||
+9
-5
@@ -204,8 +204,12 @@ requires `HTTP2-Settings`, and becomes HTTP/2 stream 1 after `101`. Optional dow
|
|||||||
remains a separate QUIC listener capability (see HTTP3.md).
|
remains a separate QUIC listener capability (see HTTP3.md).
|
||||||
|
|
||||||
Pool keepalive settings configure idle connection reuse, idle timeout/limit, TCP
|
Pool keepalive settings configure idle connection reuse, idle timeout/limit, TCP
|
||||||
keepalive and HTTP/2 active-connection pings. Health probes are separate no-reuse
|
keepalive and HTTP/2 active-connection pings. They also bound each backend Hyper client
|
||||||
HTTP/1.1 or raw TCP operations; their concurrency cap is 16. Existing active exchanges
|
generation by request count/age and cap the upstream HTTP/1 adaptive read buffer. Client
|
||||||
are not killed by disabling reuse or draining a member. Config publication rebuilds
|
generation recycling is local to the backend pool and does not publish a new vhost
|
||||||
client pools while preserving compatible observations and existing exchange leases.
|
snapshot or purge cache. Health probes are separate no-reuse HTTP/1.1 or raw TCP
|
||||||
The full contract and bounds are in VHOSTS.md. Keepalived/VRRP is not involved.
|
operations; their concurrency cap is 16. Existing active exchanges are not intentionally
|
||||||
|
killed by disabling reuse, recycling a generation or draining a member. Config
|
||||||
|
publication still rebuilds client pools while preserving compatible observations and
|
||||||
|
existing exchange leases. The full contract and bounds are in VHOSTS.md. Keepalived/VRRP
|
||||||
|
is not involved.
|
||||||
+12
-4
@@ -194,13 +194,21 @@ origin do not expose a selected backend or stale origin timing.
|
|||||||
| `idle_timeout_seconds` | 30 | 1..3600 |
|
| `idle_timeout_seconds` | 30 | 1..3600 |
|
||||||
| `max_idle_per_host` | 4 | 1..64 |
|
| `max_idle_per_host` | 4 | 1..64 |
|
||||||
| `tcp_keepalive_seconds` | 30 | 1..3600 |
|
| `tcp_keepalive_seconds` | 30 | 1..3600 |
|
||||||
|
| `pool_recycle_requests` | 25000 | 0 (off) or 1000..10000000 |
|
||||||
|
| `pool_recycle_seconds` | 3600 | 0 (off) or 60..604800 |
|
||||||
|
| `http1_max_buffer_bytes` | 131072 | 8192..1048576 |
|
||||||
|
|
||||||
These configure HTTP idle reuse and TCP keepalive; HTTP/2 also uses pings for active
|
These configure HTTP idle reuse and TCP keepalive; HTTP/2 also uses pings for active
|
||||||
connections, with a 10-second ping timeout and no pinging solely to keep idle
|
connections, with a 10-second ping timeout and no pinging solely to keep idle
|
||||||
connections alive. Disabling reuse sets the idle pool limit to zero and disables
|
connections alive. `pool_recycle_requests` and `pool_recycle_seconds` bound the lifetime
|
||||||
those keepalive probes. It does not abort already active requests/tunnels. The idle
|
of each backend Hyper client generation. Recycling swaps only that backend client/pool;
|
||||||
limit is not a separate per-backend active-request cap; global connection/exchange
|
it does not reload the vhost, purge cache or intentionally abort active exchanges. The
|
||||||
bounds still apply. HTTP health probes use separate no-reuse HTTP/1.1 connections.
|
request counter is per backend client generation, not per TCP connection. Setting either
|
||||||
|
recycle value to `0` disables that trigger independently. `http1_max_buffer_bytes` bounds
|
||||||
|
Hyper's adaptive upstream HTTP/1 read buffer per connection; it does not apply to HTTP/2.
|
||||||
|
Disabling reuse sets the idle pool limit to zero and disables keepalive probes. The idle
|
||||||
|
limit is not a separate per-backend active-request cap; global connection/exchange bounds
|
||||||
|
still apply. HTTP health probes use separate no-reuse HTTP/1.1 connections.
|
||||||
|
|
||||||
`http2` over HTTPS prefers h2 but keeps HTTP/1.1 ALPN compatibility. Over plaintext,
|
`http2` over HTTPS prefers h2 but keeps HTTP/1.1 ALPN compatibility. Over plaintext,
|
||||||
`http2` remains explicit prior-knowledge h2c with no retry-based downgrade. `auto`
|
`http2` remains explicit prior-knowledge h2c with no retry-based downgrade. `auto`
|
||||||
|
|||||||
@@ -82,7 +82,10 @@
|
|||||||
"enabled": true,
|
"enabled": true,
|
||||||
"idle_timeout_seconds": 30,
|
"idle_timeout_seconds": 30,
|
||||||
"max_idle_per_host": 4,
|
"max_idle_per_host": 4,
|
||||||
"tcp_keepalive_seconds": 30
|
"tcp_keepalive_seconds": 30,
|
||||||
|
"pool_recycle_requests": 25000,
|
||||||
|
"pool_recycle_seconds": 3600,
|
||||||
|
"http1_max_buffer_bytes": 131072
|
||||||
},
|
},
|
||||||
"sticky": {
|
"sticky": {
|
||||||
"mode": "cookie",
|
"mode": "cookie",
|
||||||
|
|||||||
@@ -70,7 +70,10 @@
|
|||||||
"enabled": true,
|
"enabled": true,
|
||||||
"idle_timeout_seconds": 30,
|
"idle_timeout_seconds": 30,
|
||||||
"max_idle_per_host": 4,
|
"max_idle_per_host": 4,
|
||||||
"tcp_keepalive_seconds": 30
|
"tcp_keepalive_seconds": 30,
|
||||||
|
"pool_recycle_requests": 25000,
|
||||||
|
"pool_recycle_seconds": 3600,
|
||||||
|
"http1_max_buffer_bytes": 131072
|
||||||
},
|
},
|
||||||
"sticky": {
|
"sticky": {
|
||||||
"mode": "off",
|
"mode": "off",
|
||||||
|
|||||||
+1
-1
@@ -19,7 +19,7 @@ classes, cache outcomes, capture-state gauges and configured-route traffic. Raw
|
|||||||
are intentionally absent from Prometheus labels.
|
are intentionally absent from Prometheus labels.
|
||||||
|
|
||||||
Import the JSON in Grafana and select a Prometheus datasource when prompted. The
|
Import the JSON in Grafana and select a Prometheus datasource when prompted. The
|
||||||
dashboard expects RustProxy 0.25.5 metric names and a scrape interval around 15s.
|
dashboard expects RustProxy 0.25.6 metric names and a scrape interval around 15s.
|
||||||
Collectors can be disabled in RustProxy settings; panels for disabled collectors
|
Collectors can be disabled in RustProxy settings; panels for disabled collectors
|
||||||
will simply show no series.
|
will simply show no series.
|
||||||
|
|
||||||
|
|||||||
@@ -4193,9 +4193,9 @@
|
|||||||
},
|
},
|
||||||
"timepicker": {},
|
"timepicker": {},
|
||||||
"timezone": "browser",
|
"timezone": "browser",
|
||||||
"title": "RustProxy 0.25.5 - Operations",
|
"title": "RustProxy 0.25.6 - Operations",
|
||||||
"uid": "rustproxy-0170",
|
"uid": "rustproxy-0170",
|
||||||
"version": 4,
|
"version": 4,
|
||||||
"weekStart": "",
|
"weekStart": "",
|
||||||
"description": "RustProxy 0.25.5 operations dashboard including bounded Traffic analytics, country and User-Agent-family visibility, and built-in Web Server traffic."
|
"description": "RustProxy 0.25.6 operations dashboard including bounded Traffic analytics, country and User-Agent-family visibility, and built-in Web Server traffic."
|
||||||
}
|
}
|
||||||
+10
-2
@@ -311,6 +311,10 @@
|
|||||||
"vhErrors": "Errors",
|
"vhErrors": "Errors",
|
||||||
"vhLatency": "Latency (EWMA)",
|
"vhLatency": "Latency (EWMA)",
|
||||||
"vhTraffic": "Traffic/s",
|
"vhTraffic": "Traffic/s",
|
||||||
|
"vhClientGeneration": "Client gen.",
|
||||||
|
"vhGenerationRequests": "Gen. requests",
|
||||||
|
"vhGenerationAge": "Gen. age",
|
||||||
|
"vhClientRotations": "Rotations",
|
||||||
"vhIntro": "Each vhost owns its bound IPs, paths and backends. Unlisted addresses cannot reach it. Listener changes require restart.",
|
"vhIntro": "Each vhost owns its bound IPs, paths and backends. Unlisted addresses cannot reach it. Listener changes require restart.",
|
||||||
"vhList": "Virtual hosts",
|
"vhList": "Virtual hosts",
|
||||||
"vhSearch": "Search vhosts",
|
"vhSearch": "Search vhosts",
|
||||||
@@ -1954,6 +1958,10 @@
|
|||||||
"aboutLicense": "License",
|
"aboutLicense": "License",
|
||||||
"aboutLicenseValue": "Open Source",
|
"aboutLicenseValue": "Open Source",
|
||||||
"aboutOpenSourceText": "RustProxy is an open-source project. Its source code is publicly available for inspection, development and community contribution.",
|
"aboutOpenSourceText": "RustProxy is an open-source project. Its source code is publicly available for inspection, development and community contribution.",
|
||||||
"aboutRepository": "Source repository"
|
"aboutRepository": "Source repository",
|
||||||
|
"vhPoolRecycleRequests": "Recycle upstream pool after requests (0 = off)",
|
||||||
|
"vhPoolRecycleSeconds": "Maximum upstream pool age (seconds, 0 = off)",
|
||||||
|
"vhHttp1MaxBuffer": "HTTP/1 upstream max read buffer (bytes)",
|
||||||
|
"vhPoolRecycleHelp": "Recycling replaces only the Hyper client generation for each backend; active exchanges continue normally. Defaults bound long-lived pool/TLS buffer retention without reloading the vhost or cache. Request recycling accepts 0 or 1000..10000000; age accepts 0 or 60..604800."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+10
-2
@@ -311,6 +311,10 @@
|
|||||||
"vhErrors": "Błędy",
|
"vhErrors": "Błędy",
|
||||||
"vhLatency": "Opóźnienie (EWMA)",
|
"vhLatency": "Opóźnienie (EWMA)",
|
||||||
"vhTraffic": "Transfer/s",
|
"vhTraffic": "Transfer/s",
|
||||||
|
"vhClientGeneration": "Gen. klienta",
|
||||||
|
"vhGenerationRequests": "Żądania gen.",
|
||||||
|
"vhGenerationAge": "Wiek gen.",
|
||||||
|
"vhClientRotations": "Rotacje",
|
||||||
"vhIntro": "Każdy vhost ma własne adresy IP, ścieżki i backendy. Inne adresy go nie obsługują. Zmiana nasłuchu wymaga restartu.",
|
"vhIntro": "Każdy vhost ma własne adresy IP, ścieżki i backendy. Inne adresy go nie obsługują. Zmiana nasłuchu wymaga restartu.",
|
||||||
"vhList": "Hosty wirtualne",
|
"vhList": "Hosty wirtualne",
|
||||||
"vhSearch": "Szukaj vhostów",
|
"vhSearch": "Szukaj vhostów",
|
||||||
@@ -1954,6 +1958,10 @@
|
|||||||
"aboutLicense": "Licencja",
|
"aboutLicense": "Licencja",
|
||||||
"aboutLicenseValue": "Open Source",
|
"aboutLicenseValue": "Open Source",
|
||||||
"aboutOpenSourceText": "RustProxy jest projektem open source. Kod źródłowy jest publicznie dostępny do wglądu, rozwoju i współtworzenia.",
|
"aboutOpenSourceText": "RustProxy jest projektem open source. Kod źródłowy jest publicznie dostępny do wglądu, rozwoju i współtworzenia.",
|
||||||
"aboutRepository": "Repozytorium źródłowe"
|
"aboutRepository": "Repozytorium źródłowe",
|
||||||
|
"vhPoolRecycleRequests": "Odśwież pulę upstream po liczbie żądań (0 = wył.)",
|
||||||
|
"vhPoolRecycleSeconds": "Maks. wiek puli upstream (sekundy, 0 = wył.)",
|
||||||
|
"vhHttp1MaxBuffer": "Maks. bufor odczytu HTTP/1 upstream (bajty)",
|
||||||
|
"vhPoolRecycleHelp": "Odświeżanie podmienia tylko generację klienta Hyper danego backendu; aktywne wymiany kończą się normalnie. Domyślne limity ograniczają retencję pamięci puli/TLS bez przeładowania vhosta ani cache. Limit żądań: 0 lub 1000..10000000; limit czasu: 0 lub 60..604800."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+1
-1
@@ -88,7 +88,7 @@ def add_file(archive: zipfile.ZipFile, rel: Path, data: bytes, timestamp: tuple[
|
|||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
parser = argparse.ArgumentParser(description=__doc__)
|
parser = argparse.ArgumentParser(description=__doc__)
|
||||||
parser.add_argument('output', nargs='?', type=Path, default=ROOT.parent / 'RustProxy-0.25.5.zip')
|
parser.add_argument('output', nargs='?', type=Path, default=ROOT.parent / 'RustProxy-0.25.6.zip')
|
||||||
output = parser.parse_args().output.resolve()
|
output = parser.parse_args().output.resolve()
|
||||||
paths = files()
|
paths = files()
|
||||||
checksum = ROOT / 'SHA256SUMS'
|
checksum = ROOT / 'SHA256SUMS'
|
||||||
|
|||||||
+13
-11
@@ -24,7 +24,7 @@ def read_docker_agent_source() -> str:
|
|||||||
|
|
||||||
preflight(root)
|
preflight(root)
|
||||||
manifest = tomllib.loads((root / "Cargo.toml").read_text())
|
manifest = tomllib.loads((root / "Cargo.toml").read_text())
|
||||||
assert manifest["package"]["version"] == "0.25.5"
|
assert manifest["package"]["version"] == "0.25.6"
|
||||||
assert manifest["dependencies"]["quinn"]["version"] == "0.11.12"
|
assert manifest["dependencies"]["quinn"]["version"] == "0.11.12"
|
||||||
h3dep = manifest["dependencies"]["h3"]
|
h3dep = manifest["dependencies"]["h3"]
|
||||||
assert h3dep["package"] == "hpx-h3" and h3dep["version"] == "=2.5.19" and "quinn" in h3dep["features"]
|
assert h3dep["package"] == "hpx-h3" and h3dep["version"] == "=2.5.19" and "quinn" in h3dep["features"]
|
||||||
@@ -32,14 +32,14 @@ assert "h3-quinn" not in manifest["dependencies"]
|
|||||||
lock_path = root / "Cargo.lock"
|
lock_path = root / "Cargo.lock"
|
||||||
if lock_path.exists():
|
if lock_path.exists():
|
||||||
lock = lock_path.read_text()
|
lock = lock_path.read_text()
|
||||||
assert 'name = "rust-proxy"\nversion = "0.25.5"' in lock
|
assert 'name = "rust-proxy"\nversion = "0.25.6"' in lock
|
||||||
assert 'name = "systemstat"' in lock and 'name = "metrics-process"' in lock and 'name = "sysinfo"' in lock, "Cargo.lock must be resolver-generated after adding cross-platform statistics libraries"
|
assert 'name = "systemstat"' in lock and 'name = "metrics-process"' in lock and 'name = "sysinfo"' in lock, "Cargo.lock must be resolver-generated after adding cross-platform statistics libraries"
|
||||||
for release_doc, marker in {
|
for release_doc, marker in {
|
||||||
"README.md": "# RustProxy 0.25.5",
|
"README.md": "# RustProxy 0.25.6",
|
||||||
"CHANGELOG.md": "## 0.25.5",
|
"CHANGELOG.md": "## 0.25.6",
|
||||||
"ROADMAP.md": "## 0.25.5",
|
"ROADMAP.md": "## 0.25.6",
|
||||||
"AGENTS.md": "Current source version: 0.25.5.",
|
"AGENTS.md": "Current source version: 0.25.6.",
|
||||||
"docs/TEST_REPORT.md": "# Verification report - RustProxy 0.25.5",
|
"docs/TEST_REPORT.md": "# Verification report - RustProxy 0.25.6",
|
||||||
}.items():
|
}.items():
|
||||||
assert marker in (root / release_doc).read_text(), f"stale release identity in {release_doc}"
|
assert marker in (root / release_doc).read_text(), f"stale release identity in {release_doc}"
|
||||||
assert tomllib.loads((root / "rust-toolchain.toml").read_text())["toolchain"]["channel"] == "stable"
|
assert tomllib.loads((root / "rust-toolchain.toml").read_text())["toolchain"]["channel"] == "stable"
|
||||||
@@ -231,7 +231,7 @@ assert 'Opt-in health decisions based on ordinary user traffic. Defaults to disa
|
|||||||
assert '"force_ssl"' in openapi and '"forward_client_ip"' in openapi
|
assert '"force_ssl"' in openapi and '"forward_client_ip"' in openapi
|
||||||
assert '"backend_header"' in openapi and '"backend_timing_header"' in openapi
|
assert '"backend_header"' in openapi and '"backend_timing_header"' in openapi
|
||||||
assert '"StreamMetrics"' in openapi and '"streams"' in openapi
|
assert '"StreamMetrics"' in openapi and '"streams"' in openapi
|
||||||
for marker in ['"version": "0.25.5"', '"/api/traffic"', '"capture_user_agent"', '"capture_country"', '"hot_auto_trim_enabled"', '"hot_auto_trim_after_seconds"', '"hot_auto_trim_target_percent"', '"/api/config/{section}"', '"ConfigSectionUpdate"', '"cold_on_idle"', '"cold_on_age"', '"cold_max_hot_seconds"', '"cold_on_lru"', '"cold_on_shutdown"', '"cold_gc_interval_seconds"', '"cold_gc_max_delete"', '"collapse_enabled"', '"collapse_wait_timeout_ms"', '"collapse_timeout_fallback"', '"stale_if_error_timeout"', '"stale_if_error_connection"', '"stale_if_error_dns"', '"stale_if_error_tls"', '"stale_if_error_statuses"', '"proactive_refresh_enabled"', '"proactive_refresh_before_expiry_seconds"', '"proactive_refresh_percent"', '"proactive_refresh_max_inflight"', '"TransformSettings"', '"TransformOverrides"', '"/api/cache/cold/cleanup"', '"/api/cache/invalidate"', '"/api/cache/bans"', '"/api/cache/bans/{id}"', '"CacheInvalidationRequest"', '"CacheInvalidationResponse"', '"ColdCleanupJob"', '"match_type"', '"regex_insensitive"', '"rewrite"', '"response"', '"covered_hosts"', '"default": true']:
|
for marker in ['"version": "0.25.6"', '"/api/traffic"', '"capture_user_agent"', '"capture_country"', '"hot_auto_trim_enabled"', '"hot_auto_trim_after_seconds"', '"hot_auto_trim_target_percent"', '"/api/config/{section}"', '"ConfigSectionUpdate"', '"cold_on_idle"', '"cold_on_age"', '"cold_max_hot_seconds"', '"cold_on_lru"', '"cold_on_shutdown"', '"cold_gc_interval_seconds"', '"cold_gc_max_delete"', '"collapse_enabled"', '"collapse_wait_timeout_ms"', '"collapse_timeout_fallback"', '"stale_if_error_timeout"', '"stale_if_error_connection"', '"stale_if_error_dns"', '"stale_if_error_tls"', '"stale_if_error_statuses"', '"proactive_refresh_enabled"', '"proactive_refresh_before_expiry_seconds"', '"proactive_refresh_percent"', '"proactive_refresh_max_inflight"', '"TransformSettings"', '"TransformOverrides"', '"/api/cache/cold/cleanup"', '"/api/cache/invalidate"', '"/api/cache/bans"', '"/api/cache/bans/{id}"', '"CacheInvalidationRequest"', '"CacheInvalidationResponse"', '"ColdCleanupJob"', '"match_type"', '"regex_insensitive"', '"rewrite"', '"response"', '"covered_hosts"', '"default": true']:
|
||||||
assert marker in openapi, marker
|
assert marker in openapi, marker
|
||||||
for marker in ['"NotFoundHost"', '"not_found_hosts"', '"PrometheusSettings"', '"allow_trusted_network_without_token"', '"include_docker_vhosts"', '"include_streams"', '"include_logging"']:
|
for marker in ['"NotFoundHost"', '"not_found_hosts"', '"PrometheusSettings"', '"allow_trusted_network_without_token"', '"include_docker_vhosts"', '"include_streams"', '"include_logging"']:
|
||||||
assert marker in openapi, marker
|
assert marker in openapi, marker
|
||||||
@@ -1085,8 +1085,10 @@ for marker_0222 in [
|
|||||||
assert marker_0222 in balance_0222, marker_0222
|
assert marker_0222 in balance_0222, marker_0222
|
||||||
assert "let mut item = serde_json::Map::new();" in balance_0222
|
assert "let mut item = serde_json::Map::new();" in balance_0222
|
||||||
assert 'json!({"id":m.definition.id, "url":m.definition.url' not in balance_0222
|
assert 'json!({"id":m.definition.id, "url":m.definition.url' not in balance_0222
|
||||||
for marker_0222 in ["member-max-concurrent", "member-queue-timeout", "vhLastFailure", "vhLastRecovery"]:
|
for marker_0222 in ["member-max-concurrent", "member-queue-timeout", "vhLastFailure", "vhLastRecovery", "vhClientGeneration", "vhGenerationRequests", "vhGenerationAge", "vhClientRotations"]:
|
||||||
assert marker_0222 in vhosts_0222 or marker_0222 in html, marker_0222
|
assert marker_0222 in vhosts_0222 or marker_0222 in html, marker_0222
|
||||||
|
for marker_0256 in ["upstream_client_generation", "upstream_client_generation_requests", "upstream_client_generation_age_seconds", "upstream_client_rotations_total"]:
|
||||||
|
assert marker_0256 in vhosts_0222, marker_0256
|
||||||
for marker_0222 in ["CertificateMetadata", "certificate_public_metadata", "x509_time_parser_handles_utc_and_generalized_time_with_offsets"]:
|
for marker_0222 in ["CertificateMetadata", "certificate_public_metadata", "x509_time_parser_handles_utc_and_generalized_time_with_offsets"]:
|
||||||
assert marker_0222 in rust_source(root, "src/tls.rs"), marker_0222
|
assert marker_0222 in rust_source(root, "src/tls.rs"), marker_0222
|
||||||
for marker_0222 in [
|
for marker_0222 in [
|
||||||
@@ -1192,7 +1194,7 @@ assert '"error_log" => {' not in admin_0241 and 'request("/api/config/error_log"
|
|||||||
assert '"error_log"' in openapi and 'logging, error_log, forwarding' not in openapi
|
assert '"error_log"' in openapi and 'logging, error_log, forwarding' not in openapi
|
||||||
assert 'logging_section_persists_error_log_settings_atomically' in admin_0241 and 'error_log_is_not_a_standalone_configuration_section' in admin_0241
|
assert 'logging_section_persists_error_log_settings_atomically' in admin_0241 and 'error_log_is_not_a_standalone_configuration_section' in admin_0241
|
||||||
assert 'location.pathname === "/logging"' in settings_js_0241
|
assert 'location.pathname === "/logging"' in settings_js_0241
|
||||||
assert '"RuntimeInformation"' in openapi and '"version": "0.25.5"' in openapi
|
assert '"RuntimeInformation"' in openapi and '"version": "0.25.6"' in openapi
|
||||||
|
|
||||||
# 0.24.1 compiler and hostname-cardinality regressions.
|
# 0.24.1 compiler and hostname-cardinality regressions.
|
||||||
tls_0241 = rust_source(root, "src/tls.rs")
|
tls_0241 = rust_source(root, "src/tls.rs")
|
||||||
@@ -1237,5 +1239,5 @@ for schema_name in ["RedirectHost", "NotFoundHost"]:
|
|||||||
node = openapi_0241["components"]["schemas"][schema_name]["properties"]["frontend"]["properties"]["hosts"]
|
node = openapi_0241["components"]["schemas"][schema_name]["properties"]["frontend"]["properties"]["hosts"]
|
||||||
assert "maxItems" not in node, schema_name
|
assert "maxItems" not in node, schema_name
|
||||||
|
|
||||||
print("PASS: 0.25.5 manifest/package, shared system-statistics/runtime metadata, Settings logging, retained H2, Debian/Grafana/Prometheus/404-host/custom-location/path/cache/dashboard/Nagios UI/source contracts, stopped legacy-renewal removal, session/admin/transport contracts, deterministic package source and embedded SQLite schema-v8 migrations.")
|
print("PASS: 0.25.6 manifest/package, shared system-statistics/runtime metadata, Settings logging, retained H2, Debian/Grafana/Prometheus/404-host/custom-location/path/cache/dashboard/Nagios UI/source contracts, stopped legacy-renewal removal, session/admin/transport contracts, deterministic package source and embedded SQLite schema-v8 migrations.")
|
||||||
print("NOT VERIFIED: Rust parsing, types, compilation, linking or runtime behavior. Run ./dev.sh test.")
|
print("NOT VERIFIED: Rust parsing, types, compilation, linking or runtime behavior. Run ./dev.sh test.")
|
||||||
@@ -97,7 +97,7 @@ def digest(path: Path) -> str:
|
|||||||
def fetch_https(url: str, max_bytes: int) -> bytes:
|
def fetch_https(url: str, max_bytes: int) -> bytes:
|
||||||
if urllib.parse.urlparse(url).scheme != 'https':
|
if urllib.parse.urlparse(url).scheme != 'https':
|
||||||
raise ValueError('GeoIP downloads require HTTPS.')
|
raise ValueError('GeoIP downloads require HTTPS.')
|
||||||
request = urllib.request.Request(url, headers={'User-Agent': 'RustProxy-installer/0.25.5'})
|
request = urllib.request.Request(url, headers={'User-Agent': 'RustProxy-installer/0.25.6'})
|
||||||
with urllib.request.urlopen(request, timeout=30) as response:
|
with urllib.request.urlopen(request, timeout=30) as response:
|
||||||
if urllib.parse.urlparse(response.geturl()).scheme != 'https':
|
if urllib.parse.urlparse(response.geturl()).scheme != 'https':
|
||||||
raise ValueError('GeoIP download redirected away from HTTPS.')
|
raise ValueError('GeoIP download redirected away from HTTPS.')
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
"""Rust-independent documentation/Reader consistency checks for the 0.25.5 release."""
|
"""Rust-independent documentation/Reader consistency checks for the 0.25.6 release."""
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import re
|
import re
|
||||||
from rust_source import rust_source
|
from rust_source import rust_source
|
||||||
@@ -55,13 +55,13 @@ assert '"/docs/content.json"' in admin
|
|||||||
readme = (ROOT / "README.md").read_text(encoding="utf-8")
|
readme = (ROOT / "README.md").read_text(encoding="utf-8")
|
||||||
roadmap = (ROOT / "ROADMAP.md").read_text(encoding="utf-8")
|
roadmap = (ROOT / "ROADMAP.md").read_text(encoding="utf-8")
|
||||||
changelog = (ROOT / "CHANGELOG.md").read_text(encoding="utf-8")
|
changelog = (ROOT / "CHANGELOG.md").read_text(encoding="utf-8")
|
||||||
assert readme.startswith("# RustProxy 0.25.5")
|
assert readme.startswith("# RustProxy 0.25.6")
|
||||||
assert "docs/WEB_SERVER.md" in readme and "docs/README.md" in readme
|
assert "docs/WEB_SERVER.md" in readme and "docs/README.md" in readme
|
||||||
assert readme.count("## What changed in ") == 1, "README duplicates historical release notes; use CHANGELOG/archive"
|
assert readme.count("## What changed in ") == 1, "README duplicates historical release notes; use CHANGELOG/archive"
|
||||||
assert "## Release history" in readme and "docs/ROADMAP_HISTORY.md" in readme
|
assert "## Release history" in readme and "docs/ROADMAP_HISTORY.md" in readme
|
||||||
assert roadmap.startswith("# RustProxy roadmap") and "## 0.25.5" in roadmap and "## 0.25.4" in roadmap and "## 0.25.3" in roadmap and "## 0.25.2" in roadmap and "## 0.25.1" in roadmap and "## 0.25.0" in roadmap
|
assert roadmap.startswith("# RustProxy roadmap") and "## 0.25.6" in roadmap and "## 0.25.5" in roadmap and "## 0.25.4" in roadmap and "## 0.25.3" in roadmap and "## 0.25.2" in roadmap and "## 0.25.1" in roadmap and "## 0.25.0" in roadmap
|
||||||
assert "## 0.24." not in roadmap and "## Web Server follow-up" in roadmap and "docs/ROADMAP_HISTORY.md" in roadmap
|
assert "## 0.24." not in roadmap and "## Web Server follow-up" in roadmap and "docs/ROADMAP_HISTORY.md" in roadmap
|
||||||
assert changelog.startswith("# Changelog\n") and "## 0.25.5" in changelog[:1000] and "## 0.25.4" in changelog[:1800] and "## 0.25.3" in changelog[:3000]
|
assert changelog.startswith("# Changelog\n") and "## 0.25.6" in changelog[:1000] and "## 0.25.5" in changelog[:1600] and "## 0.25.4" in changelog[:1800] and "## 0.25.3" in changelog[:3000]
|
||||||
assert "CHANGELOG_TECHNICAL_ARCHIVE.md" in changelog
|
assert "CHANGELOG_TECHNICAL_ARCHIVE.md" in changelog
|
||||||
for developer_only in ["Clean the remaining compiler warnings", "Update package/source/UI/OpenAPI/release identity", "source regressions and update release identity"]:
|
for developer_only in ["Clean the remaining compiler warnings", "Update package/source/UI/OpenAPI/release identity", "source regressions and update release identity"]:
|
||||||
assert developer_only not in changelog, f"developer-only CHANGELOG detail: {developer_only}"
|
assert developer_only not in changelog, f"developer-only CHANGELOG detail: {developer_only}"
|
||||||
|
|||||||
@@ -136,6 +136,15 @@ require(
|
|||||||
".try_acquire_owned()",
|
".try_acquire_owned()",
|
||||||
"tokio::time::timeout(DNS_TIMEOUT, lookup)",
|
"tokio::time::timeout(DNS_TIMEOUT, lookup)",
|
||||||
)
|
)
|
||||||
|
require(
|
||||||
|
"src/upstream/client.rs",
|
||||||
|
"pool_recycle_requests",
|
||||||
|
"pool_recycle_seconds",
|
||||||
|
"http1_max_buf_size(keepalive.http1_max_buffer_bytes)",
|
||||||
|
"ArcSwap<RawProxyClient>",
|
||||||
|
"self.current.store(Arc::new(client))",
|
||||||
|
'"recycled upstream client pool"',
|
||||||
|
)
|
||||||
require(
|
require(
|
||||||
"src/balance.rs",
|
"src/balance.rs",
|
||||||
"if checks.len() >= 16 { break; }",
|
"if checks.len() >= 16 { break; }",
|
||||||
|
|||||||
@@ -75,10 +75,10 @@ def check(root: Path, repair_known: bool = False) -> list[str]:
|
|||||||
raise ValueError(f"Conflicting Rust modules: {flat.relative_to(root)} and {module.relative_to(root)}")
|
raise ValueError(f"Conflicting Rust modules: {flat.relative_to(root)} and {module.relative_to(root)}")
|
||||||
for path in ["src/auth/mod.rs", "src/auth/store.rs", "src/backup/snapshot.rs", "src/upstream.rs", "src/tls.rs", "src/proxy/websocket.rs", "src/cache/mod.rs", "src/cache/model.rs", "src/cache/lifecycle.rs", "src/cache/cold.rs", "src/cache/dashboard.rs", "src/cache/tickets.rs", "src/cache/lookup.rs", "src/cache/policy.rs", "src/cache/fill.rs", "src/cache/tests.rs", "src/settings.rs", "src/compression.rs", "src/diagnostics.rs", "src/traffic.rs", "src/system_stats/mod.rs", "src/system_stats/linux.rs", "src/vhost.rs", "src/web_server/mod.rs", "src/web_server/config.rs", "src/web_server/filesystem.rs", "src/web_server/security.rs", "src/web_server/response.rs", "src/web_server/request.rs", "src/web_server/routing.rs", "src/web_server/fastcgi.rs", "src/web_server/htaccess.rs", "src/web_server/serve.rs", "src/web_server/tests.rs", "src/balance.rs", "src/security.rs", "src/admin/web/vhosts/core.js", "src/admin/web/vhosts/editor.js", "src/admin/web/vhosts/render.js", "src/admin/web/web-server.js", "src/admin/web/streams.js", "src/admin/web/host404.js", "src/admin/web/app/core.js", "src/admin/web/app/config-history.js", "src/admin/web/app/runtime.js", "src/admin/web/app/settings.js", "src/admin/web/management.js", "src/pages.rs", "scripts/mock_server.py", "scripts/mock_auth.py", "src/forwarding.rs", "src/tinyauth.rs", "src/http3.rs", "src/stream.rs", "src/admin/web/integrations.js", "src/admin/web/traffic-panel.js", "src/prometheus.rs", "src/admin/web/settings.js", "src/admin/web/docker.js", "src/docker.rs", "docker-agent/main.go", "docker-agent/model.go", "docker-agent/docker.go", "docker-agent/network.go", "docker-agent/certificate.go", "docker-agent/server.go", "docker-agent/main_test.go", "docker-agent/rustproxy-docker-agent.service", "docker-agent/install.sh", "docs/DOCKER_DISCOVERY.md", "docs/WEB_SERVER.md", "docs/PHP_FPM.md", "docs/README.md", "docs/TODO.md", "docs/V0.25.5_AUDIT.md", "docs/V0.25.4_AUDIT.md", "docs/V0.25.3_AUDIT.md", "docs/V0.25.2_AUDIT.md", "docs/CHANGELOG_TECHNICAL_ARCHIVE.md", "docs/ROADMAP_HISTORY.md", "scripts/docs_check.py", "scripts/web_server_contracts.py", "scripts/rust_source.py", "scripts/rust_module_contracts.py", "scripts/source_module_contracts.py", "scripts/acme_provider.py", "src/basic_auth.rs", "scripts/deploy.py", "scripts/deploy_core.py", "scripts/deploy_runtime.py", "scripts/migrate_npm.py", "scripts/migrate_npm_core.py", "scripts/migrate_npm_api.py", "docs/NPM_MIGRATION.md", "docs/STREAMS.md", "install.sh", "install-debian13.sh", "update.sh", "build.rs", "scripts/swagger_assets.py", "src/admin/documentation.rs", "src/admin/openapi.json", "langs/en_US.json", "langs/pl_pl.json", "Dockerfile", ".dockerignore", "docs/CONTAINER.md", "docs/PROMETHEUS.md", "docs/NOT_FOUND_HOSTS.md", "debian/control", "debian/rules", "debian/rustproxy.service", "debian/rustproxy.logrotate", "grafana/rustproxy-overview.json"]:
|
for path in ["src/auth/mod.rs", "src/auth/store.rs", "src/backup/snapshot.rs", "src/upstream.rs", "src/tls.rs", "src/proxy/websocket.rs", "src/cache/mod.rs", "src/cache/model.rs", "src/cache/lifecycle.rs", "src/cache/cold.rs", "src/cache/dashboard.rs", "src/cache/tickets.rs", "src/cache/lookup.rs", "src/cache/policy.rs", "src/cache/fill.rs", "src/cache/tests.rs", "src/settings.rs", "src/compression.rs", "src/diagnostics.rs", "src/traffic.rs", "src/system_stats/mod.rs", "src/system_stats/linux.rs", "src/vhost.rs", "src/web_server/mod.rs", "src/web_server/config.rs", "src/web_server/filesystem.rs", "src/web_server/security.rs", "src/web_server/response.rs", "src/web_server/request.rs", "src/web_server/routing.rs", "src/web_server/fastcgi.rs", "src/web_server/htaccess.rs", "src/web_server/serve.rs", "src/web_server/tests.rs", "src/balance.rs", "src/security.rs", "src/admin/web/vhosts/core.js", "src/admin/web/vhosts/editor.js", "src/admin/web/vhosts/render.js", "src/admin/web/web-server.js", "src/admin/web/streams.js", "src/admin/web/host404.js", "src/admin/web/app/core.js", "src/admin/web/app/config-history.js", "src/admin/web/app/runtime.js", "src/admin/web/app/settings.js", "src/admin/web/management.js", "src/pages.rs", "scripts/mock_server.py", "scripts/mock_auth.py", "src/forwarding.rs", "src/tinyauth.rs", "src/http3.rs", "src/stream.rs", "src/admin/web/integrations.js", "src/admin/web/traffic-panel.js", "src/prometheus.rs", "src/admin/web/settings.js", "src/admin/web/docker.js", "src/docker.rs", "docker-agent/main.go", "docker-agent/model.go", "docker-agent/docker.go", "docker-agent/network.go", "docker-agent/certificate.go", "docker-agent/server.go", "docker-agent/main_test.go", "docker-agent/rustproxy-docker-agent.service", "docker-agent/install.sh", "docs/DOCKER_DISCOVERY.md", "docs/WEB_SERVER.md", "docs/PHP_FPM.md", "docs/README.md", "docs/TODO.md", "docs/V0.25.5_AUDIT.md", "docs/V0.25.4_AUDIT.md", "docs/V0.25.3_AUDIT.md", "docs/V0.25.2_AUDIT.md", "docs/CHANGELOG_TECHNICAL_ARCHIVE.md", "docs/ROADMAP_HISTORY.md", "scripts/docs_check.py", "scripts/web_server_contracts.py", "scripts/rust_source.py", "scripts/rust_module_contracts.py", "scripts/source_module_contracts.py", "scripts/acme_provider.py", "src/basic_auth.rs", "scripts/deploy.py", "scripts/deploy_core.py", "scripts/deploy_runtime.py", "scripts/migrate_npm.py", "scripts/migrate_npm_core.py", "scripts/migrate_npm_api.py", "docs/NPM_MIGRATION.md", "docs/STREAMS.md", "install.sh", "install-debian13.sh", "update.sh", "build.rs", "scripts/swagger_assets.py", "src/admin/documentation.rs", "src/admin/openapi.json", "langs/en_US.json", "langs/pl_pl.json", "Dockerfile", ".dockerignore", "docs/CONTAINER.md", "docs/PROMETHEUS.md", "docs/NOT_FOUND_HOSTS.md", "debian/control", "debian/rules", "debian/rustproxy.service", "debian/rustproxy.logrotate", "grafana/rustproxy-overview.json"]:
|
||||||
if not (root / path).is_file():
|
if not (root / path).is_file():
|
||||||
raise ValueError(f"Incomplete RustProxy 0.25.5 source tree: missing {path}")
|
raise ValueError(f"Incomplete RustProxy 0.25.6 source tree: missing {path}")
|
||||||
text = (root / "src/lib.rs").read_text(encoding="utf-8")
|
text = (root / "src/lib.rs").read_text(encoding="utf-8")
|
||||||
if '#[path = "auth/mod.rs"]' not in text:
|
if '#[path = "auth/mod.rs"]' not in text:
|
||||||
raise ValueError("src/lib.rs is not the 0.25.5 entry point; extract the complete package, not individual files.")
|
raise ValueError("src/lib.rs is not the 0.25.6 entry point; extract the complete package, not individual files.")
|
||||||
return messages
|
return messages
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ def upgrade_smoke(tmp: Path) -> None:
|
|||||||
assert backup.is_dir()
|
assert backup.is_dir()
|
||||||
assert (backup / "src/obsolete.rs").is_file()
|
assert (backup / "src/obsolete.rs").is_file()
|
||||||
assert not (target / "src/obsolete.rs").exists()
|
assert not (target / "src/obsolete.rs").exists()
|
||||||
assert 'version = "0.25.5"' in (target / "Cargo.toml").read_text(encoding="utf-8")
|
assert 'version = "0.25.6"' in (target / "Cargo.toml").read_text(encoding="utf-8")
|
||||||
assert (target / "data/keep.txt").read_text(encoding="utf-8") == "preserve\n"
|
assert (target / "data/keep.txt").read_text(encoding="utf-8") == "preserve\n"
|
||||||
assert (target / ".env").read_text(encoding="utf-8") == "RUST_PROXY_DEMO=0\n"
|
assert (target / ".env").read_text(encoding="utf-8") == "RUST_PROXY_DEMO=0\n"
|
||||||
assert (target / "langs/site.json").is_file()
|
assert (target / "langs/site.json").is_file()
|
||||||
@@ -134,7 +134,7 @@ def upgrade_smoke(tmp: Path) -> None:
|
|||||||
assert (target / "docker-agent/certificate.go").is_file()
|
assert (target / "docker-agent/certificate.go").is_file()
|
||||||
assert (target / "docker-agent/server.go").is_file()
|
assert (target / "docker-agent/server.go").is_file()
|
||||||
manifest = json.loads((backup / "upgrade.json").read_text(encoding="utf-8"))
|
manifest = json.loads((backup / "upgrade.json").read_text(encoding="utf-8"))
|
||||||
assert manifest["to_version"] == "0.25.5"
|
assert manifest["to_version"] == "0.25.6"
|
||||||
assert manifest["removed_obsolete_runtime_state"] is True
|
assert manifest["removed_obsolete_runtime_state"] is True
|
||||||
assert not legacy.exists()
|
assert not legacy.exists()
|
||||||
assert not (backup / "legacy-data").exists()
|
assert not (backup / "legacy-data").exists()
|
||||||
@@ -545,7 +545,7 @@ def source_contract_smoke() -> None:
|
|||||||
assert marker in admin, marker
|
assert marker in admin, marker
|
||||||
anonymous_block = admin.split("fn anonymous_allowed", 1)[1].split("const CERTIFICATE_API_KEY_HEADER", 1)[0]
|
anonymous_block = admin.split("fn anonymous_allowed", 1)[1].split("const CERTIFICATE_API_KEY_HEADER", 1)[0]
|
||||||
assert '"/api/status"' not in anonymous_block
|
assert '"/api/status"' not in anonymous_block
|
||||||
assert '"RuntimeInformation"' in openapi_0241 and '"version": "0.25.5"' in openapi_0241
|
assert '"RuntimeInformation"' in openapi_0241 and '"version": "0.25.6"' in openapi_0241
|
||||||
assert 'id="panel-logging"' not in html
|
assert 'id="panel-logging"' not in html
|
||||||
for marker in ['id="settings-tab-logging"', 'id="settings-page-logging"', 'id="logging-form"', 'id="error-log-form"']:
|
for marker in ['id="settings-tab-logging"', 'id="settings-page-logging"', 'id="logging-form"', 'id="error-log-form"']:
|
||||||
assert marker in html, marker
|
assert marker in html, marker
|
||||||
@@ -1002,7 +1002,7 @@ def source_contract_smoke() -> None:
|
|||||||
assert '.managed-update' in main and "flush_hot_to_cold_for_update" in main
|
assert '.managed-update' in main and "flush_hot_to_cold_for_update" in main
|
||||||
openapi = (ROOT / "src/admin/openapi.json").read_text(encoding="utf-8")
|
openapi = (ROOT / "src/admin/openapi.json").read_text(encoding="utf-8")
|
||||||
assert '"/api/config/history/restore"' in openapi
|
assert '"/api/config/history/restore"' in openapi
|
||||||
for marker in ['"version": "0.25.5"', '"memory_preset"', '"cold_preset"', '"memory_budget_bytes"', '"max_inflight"', '"preset"', '"session_days"', '"session_lifetime_seconds"', '"accept_local_listener_risk"', '"backend_header"', '"backend_timing_header"', '"cold_on_age"', '"match_type"', '"regex_insensitive"', '"NotFoundHost"', '"not_found_hosts"', '"PrometheusSettings"', '"allow_trusted_network_without_token"', '"include_docker_vhosts"', '"include_streams"', '"include_logging"']:
|
for marker in ['"version": "0.25.6"', '"memory_preset"', '"cold_preset"', '"memory_budget_bytes"', '"max_inflight"', '"preset"', '"session_days"', '"session_lifetime_seconds"', '"accept_local_listener_risk"', '"backend_header"', '"backend_timing_header"', '"cold_on_age"', '"match_type"', '"regex_insensitive"', '"NotFoundHost"', '"not_found_hosts"', '"PrometheusSettings"', '"allow_trusted_network_without_token"', '"include_docker_vhosts"', '"include_streams"', '"include_logging"']:
|
||||||
assert marker in openapi, marker
|
assert marker in openapi, marker
|
||||||
assert '"software_update"' in openapi and '"update_available"' in openapi
|
assert '"software_update"' in openapi and '"update_available"' in openapi
|
||||||
for marker in ['"/api/certificates/deploy"', '"CertificateDeploy"', '"CertificateDeployResult"', '"/api/certificates/reload"']:
|
for marker in ['"/api/certificates/deploy"', '"CertificateDeploy"', '"CertificateDeployResult"', '"/api/certificates/reload"']:
|
||||||
@@ -1177,7 +1177,7 @@ def main() -> None:
|
|||||||
source_contract_smoke()
|
source_contract_smoke()
|
||||||
container_contract_smoke()
|
container_contract_smoke()
|
||||||
debian_grafana_contract_smoke()
|
debian_grafana_contract_smoke()
|
||||||
print("PASS: 0.25.5 SQLite/upgrade, local-response 404 hosts, Prometheus/Grafana diagnostics, Debian packaging, cache/dashboard/logging/Nagios, retained admin/H3/stream/TLS contracts and reproducible source archives.")
|
print("PASS: 0.25.6 SQLite/upgrade, local-response 404 hosts, Prometheus/Grafana diagnostics, Debian packaging, cache/dashboard/logging/Nagios, retained admin/H3/stream/TLS contracts and reproducible source archives.")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ def download(destination: Path) -> None:
|
|||||||
"""TLS verification uses Python's default trust store; never executes a shell."""
|
"""TLS verification uses Python's default trust store; never executes a shell."""
|
||||||
started = time.monotonic()
|
started = time.monotonic()
|
||||||
opener = build_opener(HttpsRedirects())
|
opener = build_opener(HttpsRedirects())
|
||||||
request = Request(DOWNLOAD_URL, headers={"User-Agent": "RustProxy-build/0.25.5"})
|
request = Request(DOWNLOAD_URL, headers={"User-Agent": "RustProxy-build/0.25.6"})
|
||||||
with opener.open(request, timeout=30) as response, destination.open("wb") as output:
|
with opener.open(request, timeout=30) as response, destination.open("wb") as output:
|
||||||
length = response.headers.get("Content-Length")
|
length = response.headers.get("Content-Length")
|
||||||
if length and int(length) > MAX_ARCHIVE:
|
if length and int(length) > MAX_ARCHIVE:
|
||||||
|
|||||||
+3
-3
@@ -46,7 +46,7 @@ def upgrade(source: Path, target: Path, *, stopped: bool, data_dir: Path | None
|
|||||||
for name in MANAGED:
|
for name in MANAGED:
|
||||||
if (target / name).is_symlink():
|
if (target / name).is_symlink():
|
||||||
raise ValueError(f"Managed target {name} is a symlink; refusing to replace it.")
|
raise ValueError(f"Managed target {name} is a symlink; refusing to replace it.")
|
||||||
backup = target / ".upgrade-backup" / ("before-0.25.5-" + uuid.uuid4().hex[:12])
|
backup = target / ".upgrade-backup" / ("before-0.25.6-" + uuid.uuid4().hex[:12])
|
||||||
backup.mkdir(parents=True, mode=0o700)
|
backup.mkdir(parents=True, mode=0o700)
|
||||||
installed: list[str] = []
|
installed: list[str] = []
|
||||||
moved: list[str] = []
|
moved: list[str] = []
|
||||||
@@ -84,7 +84,7 @@ def upgrade(source: Path, target: Path, *, stopped: bool, data_dir: Path | None
|
|||||||
remove_legacy = legacy.exists()
|
remove_legacy = legacy.exists()
|
||||||
if remove_legacy and (legacy.is_symlink() or not legacy.is_file()):
|
if remove_legacy and (legacy.is_symlink() or not legacy.is_file()):
|
||||||
raise ValueError("Obsolete renewal observation sidecar must be a regular file.")
|
raise ValueError("Obsolete renewal observation sidecar must be a regular file.")
|
||||||
(backup / "upgrade.json").write_text(json.dumps({"from_directory":str(target), "to_version":"0.25.5", "managed_paths":MANAGED, "removed_obsolete_runtime_state": remove_legacy}, indent=2)+"\n", encoding="utf-8")
|
(backup / "upgrade.json").write_text(json.dumps({"from_directory":str(target), "to_version":"0.25.6", "managed_paths":MANAGED, "removed_obsolete_runtime_state": remove_legacy}, indent=2)+"\n", encoding="utf-8")
|
||||||
if remove_legacy:
|
if remove_legacy:
|
||||||
legacy.unlink()
|
legacy.unlink()
|
||||||
except BaseException:
|
except BaseException:
|
||||||
@@ -115,7 +115,7 @@ def main() -> None:
|
|||||||
backup = upgrade(Path(__file__).resolve().parents[1], args.target, stopped=args.stopped, data_dir=data_dir)
|
backup = upgrade(Path(__file__).resolve().parents[1], args.target, stopped=args.stopped, data_dir=data_dir)
|
||||||
except (OSError, ValueError) as error:
|
except (OSError, ValueError) as error:
|
||||||
parser.exit(2, f"Upgrade refused or rolled back: {error}\n")
|
parser.exit(2, f"Upgrade refused or rolled back: {error}\n")
|
||||||
print(f"Installed RustProxy 0.25.5. Previous managed source files: {backup}")
|
print(f"Installed RustProxy 0.25.6. Previous managed source files: {backup}")
|
||||||
print("Preserved data, .env, .git, target and other unmanaged files. No database migration was run.")
|
print("Preserved data, .env, .git, target and other unmanaged files. No database migration was run.")
|
||||||
print(f"Next: cd {args.target}; ./dev.sh test; ./dev.sh")
|
print(f"Next: cd {args.target}; ./dev.sh test; ./dev.sh")
|
||||||
|
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ need(web,
|
|||||||
'HeaderValue::from_static("no-store")',
|
'HeaderValue::from_static("no-store")',
|
||||||
"builtin_error_response(StatusCode::FORBIDDEN, &method)",
|
"builtin_error_response(StatusCode::FORBIDDEN, &method)",
|
||||||
"empty_index_can_go_directly_to_directory_listing",
|
"empty_index_can_go_directly_to_directory_listing",
|
||||||
"RustProxy <b>0.25.5</b>",
|
"RustProxy <b>0.25.6</b>",
|
||||||
"traversal_and_symlink_escape_are_not_served",
|
"traversal_and_symlink_escape_are_not_served",
|
||||||
"try_files_rewrites_cache_rules_headers_and_downloads_work",
|
"try_files_rewrites_cache_rules_headers_and_downloads_work",
|
||||||
"precompressed_sidecars_keep_mime_validators_and_range_semantics",
|
"precompressed_sidecars_keep_mime_validators_and_range_semantics",
|
||||||
|
|||||||
+23
-2
@@ -2,7 +2,7 @@
|
|||||||
"openapi": "3.0.3",
|
"openapi": "3.0.3",
|
||||||
"info": {
|
"info": {
|
||||||
"title": "RustProxy Administration API",
|
"title": "RustProxy Administration API",
|
||||||
"version": "0.25.5",
|
"version": "0.25.6",
|
||||||
"description": "Administration API for the active panel origin. Sign in through the panel; the same-origin HttpOnly cookie authenticates all private operations. Mutations also require the exact Origin, X-RustProxy-Request: 1 and a session-bound X-CSRF-Token. Loopback HTTP is the default; Settings can enable HTTPS before using a non-loopback administration bind. This document contains no live configuration or credentials. Object schemas marked extensible are summaries: full configuration validation is authoritative in Rust."
|
"description": "Administration API for the active panel origin. Sign in through the panel; the same-origin HttpOnly cookie authenticates all private operations. Mutations also require the exact Origin, X-RustProxy-Request: 1 and a session-bound X-CSRF-Token. Loopback HTTP is the default; Settings can enable HTTPS before using a non-loopback administration bind. This document contains no live configuration or credentials. Object schemas marked extensible are summaries: full configuration validation is authoritative in Rust."
|
||||||
},
|
},
|
||||||
"servers": [
|
"servers": [
|
||||||
@@ -3153,6 +3153,27 @@
|
|||||||
"minimum": 1,
|
"minimum": 1,
|
||||||
"maximum": 3600,
|
"maximum": 3600,
|
||||||
"default": 30
|
"default": 30
|
||||||
|
},
|
||||||
|
"pool_recycle_requests": {
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 0,
|
||||||
|
"maximum": 10000000,
|
||||||
|
"default": 25000,
|
||||||
|
"description": "Maximum requests handled by one backend Hyper client generation before its connection pool is recycled. 0 disables request-count recycling; nonzero values below 1000 are rejected by configuration validation."
|
||||||
|
},
|
||||||
|
"pool_recycle_seconds": {
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 0,
|
||||||
|
"maximum": 604800,
|
||||||
|
"default": 3600,
|
||||||
|
"description": "Maximum age in seconds of one backend Hyper client generation. 0 disables age-based recycling; nonzero values below 60 are rejected by configuration validation."
|
||||||
|
},
|
||||||
|
"http1_max_buffer_bytes": {
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 8192,
|
||||||
|
"maximum": 1048576,
|
||||||
|
"default": 131072,
|
||||||
|
"description": "Maximum adaptive read-buffer size per upstream HTTP/1 connection."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -9376,4 +9397,4 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6,7 +6,7 @@ function renderSettings() {
|
|||||||
if (!settingsDirty.has("response-form")) {
|
if (!settingsDirty.has("response-form")) {
|
||||||
const server = config.server_header || {}, compression = config.compression || {}, diagnostics = config.diagnostic_headers || {};
|
const server = config.server_header || {}, compression = config.compression || {}, diagnostics = config.diagnostic_headers || {};
|
||||||
$("expose-request-id").checked = !!diagnostics.request_id;
|
$("expose-request-id").checked = !!diagnostics.request_id;
|
||||||
$("server-mode").value = server.mode || "preserve"; $("server-value").value = server.value || "RustProxy/v0.25.5";
|
$("server-mode").value = server.mode || "preserve"; $("server-value").value = server.value || "RustProxy/v0.25.6";
|
||||||
for (const name of ["gzip", "br", "zstd", "deflate"]) $(`compress-${name}`).checked = !!compression[name];
|
for (const name of ["gzip", "br", "zstd", "deflate"]) $(`compress-${name}`).checked = !!compression[name];
|
||||||
$("compress-min").value = compression.min_bytes ?? 1024; syncServerMode();
|
$("compress-min").value = compression.min_bytes ?? 1024; syncServerMode();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -541,6 +541,10 @@
|
|||||||
<th data-i18n="vhErrors">Errors</th>
|
<th data-i18n="vhErrors">Errors</th>
|
||||||
<th data-i18n="vhLatency">Latency</th>
|
<th data-i18n="vhLatency">Latency</th>
|
||||||
<th data-i18n="vhTraffic">Traffic/s</th>
|
<th data-i18n="vhTraffic">Traffic/s</th>
|
||||||
|
<th data-i18n="vhClientGeneration">Client gen.</th>
|
||||||
|
<th data-i18n="vhGenerationRequests">Gen. requests</th>
|
||||||
|
<th data-i18n="vhGenerationAge">Gen. age</th>
|
||||||
|
<th data-i18n="vhClientRotations">Rotations</th>
|
||||||
<th data-i18n="vhLastFailure">Last failure</th>
|
<th data-i18n="vhLastFailure">Last failure</th>
|
||||||
<th data-i18n="vhLastRecovery">Last recovery</th>
|
<th data-i18n="vhLastRecovery">Last recovery</th>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -1594,7 +1598,7 @@
|
|||||||
<option data-i18n="serverCustom" value="custom">Replace / add custom value</option>
|
<option data-i18n="serverCustom" value="custom">Replace / add custom value</option>
|
||||||
</select>
|
</select>
|
||||||
<label data-i18n="serverValue" for="server-value">Custom Server value</label><input
|
<label data-i18n="serverValue" for="server-value">Custom Server value</label><input
|
||||||
id="server-value" maxlength="256" placeholder="RustProxy/v0.25.5"
|
id="server-value" maxlength="256" placeholder="RustProxy/v0.25.6"
|
||||||
spellcheck="false" />
|
spellcheck="false" />
|
||||||
<h3 class="subheading" data-i18n="diagnosticHeaders">Diagnostic headers</h3>
|
<h3 class="subheading" data-i18n="diagnosticHeaders">Diagnostic headers</h3>
|
||||||
<div class="switch-grid">
|
<div class="switch-grid">
|
||||||
@@ -2382,7 +2386,7 @@
|
|||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<footer class="page-footer"><span>RustProxy <b>0.25.5</b></span><span id="footer-status">API - /
|
<footer class="page-footer"><span>RustProxy <b>0.25.6</b></span><span id="footer-status">API - /
|
||||||
dropped: 0</span></footer>
|
dropped: 0</span></footer>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
@@ -3093,7 +3097,7 @@ max_execution_time = 30</code></pre>
|
|||||||
<article class="card about-card">
|
<article class="card about-card">
|
||||||
<div class="about-product">
|
<div class="about-product">
|
||||||
<span aria-hidden="true" class="brand-mark">r<span>/</span>p</span>
|
<span aria-hidden="true" class="brand-mark">r<span>/</span>p</span>
|
||||||
<div><span class="small-label">RustProxy</span><strong>0.25.5</strong></div>
|
<div><span class="small-label">RustProxy</span><strong>0.25.6</strong></div>
|
||||||
</div>
|
</div>
|
||||||
<dl class="about-meta">
|
<dl class="about-meta">
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -112,6 +112,10 @@
|
|||||||
field(g, "idle-timeout", "vhIdleTimeout", keepalive.idle_timeout_seconds ?? 30, "number", { required: true, min: 1, max: 3600 });
|
field(g, "idle-timeout", "vhIdleTimeout", keepalive.idle_timeout_seconds ?? 30, "number", { required: true, min: 1, max: 3600 });
|
||||||
field(g, "max-idle", "vhMaxIdle", keepalive.max_idle_per_host ?? 4, "number", { required: true, min: 1, max: 64 });
|
field(g, "max-idle", "vhMaxIdle", keepalive.max_idle_per_host ?? 4, "number", { required: true, min: 1, max: 64 });
|
||||||
field(g, "tcp-keepalive", "vhTcpKeepalive", keepalive.tcp_keepalive_seconds ?? 30, "number", { required: true, min: 1, max: 3600 });
|
field(g, "tcp-keepalive", "vhTcpKeepalive", keepalive.tcp_keepalive_seconds ?? 30, "number", { required: true, min: 1, max: 3600 });
|
||||||
|
field(g, "pool-recycle-requests", "vhPoolRecycleRequests", keepalive.pool_recycle_requests ?? 25000, "number", { required: true, min: 0, max: 10000000 });
|
||||||
|
field(g, "pool-recycle-seconds", "vhPoolRecycleSeconds", keepalive.pool_recycle_seconds ?? 3600, "number", { required: true, min: 0, max: 604800 });
|
||||||
|
field(g, "http1-max-buffer", "vhHttp1MaxBuffer", keepalive.http1_max_buffer_bytes ?? 131072, "number", { required: true, min: 8192, max: 1048576 });
|
||||||
|
note(g, "vhPoolRecycleHelp");
|
||||||
g = group("vhHealth"); const healthMode = field(g, "health-mode", "vhHealthMode", health.mode || "tcp", "select", { values: [["off", "vhOff"], ["tcp", "vhTcp"], ["http", "vhHttp"]] });
|
g = group("vhHealth"); const healthMode = field(g, "health-mode", "vhHealthMode", health.mode || "tcp", "select", { values: [["off", "vhOff"], ["tcp", "vhTcp"], ["http", "vhHttp"]] });
|
||||||
const healthOffWarning = note(g, "vhHealthOffWarning"); const syncHealthWarning = () => { healthOffWarning.hidden = healthMode.value !== "off"; }; healthMode.addEventListener("change", syncHealthWarning); syncHealthWarning();
|
const healthOffWarning = note(g, "vhHealthOffWarning"); const syncHealthWarning = () => { healthOffWarning.hidden = healthMode.value !== "off"; }; healthMode.addEventListener("change", syncHealthWarning); syncHealthWarning();
|
||||||
field(g, "health-path", "vhHealthPath", health.path || "/", "text", { required: true, maxLength: 1024 });
|
field(g, "health-path", "vhHealthPath", health.path || "/", "text", { required: true, maxLength: 1024 });
|
||||||
@@ -317,7 +321,7 @@
|
|||||||
diagnostic_headers: yes("diag-inherit") ? null : { request_id: yes("diag-request_id") },
|
diagnostic_headers: yes("diag-inherit") ? null : { request_id: yes("diag-request_id") },
|
||||||
tinyauth: { enabled: yes("auth-enabled"), url: str("auth-url"), login_url: str("auth-login"), allow_private: yes("auth-private"), redirect_forbidden: yes("auth-redirect-forbidden"), connect_timeout_seconds: num("auth-connect"), timeout_seconds: num("auth-timeout"), request_headers: lines(str("auth-request-headers")), response_headers: lines(str("auth-response-headers")), address_allowlist: lines(str("auth-allowlist")), tls_ca_pem: nullable("auth-ca") }, backends: members, routes: paths, acl, headers,
|
tinyauth: { enabled: yes("auth-enabled"), url: str("auth-url"), login_url: str("auth-login"), allow_private: yes("auth-private"), redirect_forbidden: yes("auth-redirect-forbidden"), connect_timeout_seconds: num("auth-connect"), timeout_seconds: num("auth-timeout"), request_headers: lines(str("auth-request-headers")), response_headers: lines(str("auth-response-headers")), address_allowlist: lines(str("auth-allowlist")), tls_ca_pem: nullable("auth-ca") }, backends: members, routes: paths, acl, headers,
|
||||||
load_balancing: {
|
load_balancing: {
|
||||||
algorithm: str("algorithm"), slow_start_seconds: num("slow-start"), keepalive: { enabled: yes("keepalive"), idle_timeout_seconds: num("idle-timeout"), max_idle_per_host: num("max-idle"), tcp_keepalive_seconds: num("tcp-keepalive") },
|
algorithm: str("algorithm"), slow_start_seconds: num("slow-start"), keepalive: { enabled: yes("keepalive"), idle_timeout_seconds: num("idle-timeout"), max_idle_per_host: num("max-idle"), tcp_keepalive_seconds: num("tcp-keepalive"), pool_recycle_requests: num("pool-recycle-requests"), pool_recycle_seconds: num("pool-recycle-seconds"), http1_max_buffer_bytes: num("http1-max-buffer") },
|
||||||
retry: { max_retries: num("retry-max"), retry_connect_errors: yes("retry-connect"), retry_timeouts: yes("retry-timeouts"), retry_statuses: str("retry-statuses").split(/[\s,]+/).filter(Boolean).map(value => Number(value)) },
|
retry: { max_retries: num("retry-max"), retry_connect_errors: yes("retry-connect"), retry_timeouts: yes("retry-timeouts"), retry_statuses: str("retry-statuses").split(/[\s,]+/).filter(Boolean).map(value => Number(value)) },
|
||||||
health_check: { mode: str("health-mode"), path: str("health-path"), host: nullable("health-host"), interval_ms: num("interval"), timeout_ms: num("timeout"), slow_response_ms: num("slow"), fall: num("fall"), rise: num("rise"), expected_status_min: num("status-min"), expected_status_max: num("status-max") },
|
health_check: { mode: str("health-mode"), path: str("health-path"), host: nullable("health-host"), interval_ms: num("interval"), timeout_ms: num("timeout"), slow_response_ms: num("slow"), fall: num("fall"), rise: num("rise"), expected_status_min: num("status-min"), expected_status_max: num("status-max") },
|
||||||
passive_health: {
|
passive_health: {
|
||||||
|
|||||||
@@ -142,9 +142,12 @@
|
|||||||
const lastFailure = Number(member.last_failure_at_ms) > 0 ? `${member.last_failure_class || "-"} · ${new Date(member.last_failure_at_ms).toLocaleTimeString(locale())}` : "-";
|
const lastFailure = Number(member.last_failure_at_ms) > 0 ? `${member.last_failure_class || "-"} · ${new Date(member.last_failure_at_ms).toLocaleTimeString(locale())}` : "-";
|
||||||
const lastRecovery = Number(member.last_recovered_ms) > 0 ? new Date(member.last_recovered_ms).toLocaleTimeString(locale()) : "-";
|
const lastRecovery = Number(member.last_recovered_ms) > 0 ? new Date(member.last_recovered_ms).toLocaleTimeString(locale()) : "-";
|
||||||
const healthDetail = `${t("vhActiveHealth")}: ${member.last_result || "-"} · ${t("vhPassiveFailures")}: ${member.passive_failures ?? 0} (${member.last_passive_result || "-"})`;
|
const healthDetail = `${t("vhActiveHealth")}: ${member.last_result || "-"} · ${t("vhPassiveFailures")}: ${member.passive_failures ?? 0} (${member.last_passive_result || "-"})`;
|
||||||
|
const generationAgeRaw = member.upstream_client_generation_age_seconds;
|
||||||
|
const generationAge = Math.max(0, Number(generationAgeRaw));
|
||||||
|
const generationAgeText = generationAgeRaw == null || !Number.isFinite(generationAge) ? "-" : generationAge >= 3600 ? `${Math.floor(generationAge / 3600)}h ${Math.floor((generationAge % 3600) / 60)}m` : generationAge >= 60 ? `${Math.floor(generationAge / 60)}m ${Math.floor(generationAge % 60)}s` : `${Math.floor(generationAge)}s`;
|
||||||
const row = el("tr"); if (vhostDisabled) row.classList.add("pool-vhost-disabled"); const poolDomain = status.backend_pool_domains?.[pool.id]; const poolLabel = poolDomain ? `${pool.id} (${poolDomain})` : pool.id; const cells = [poolLabel, `${member.id}${member.backup ? " / " + t("vhBackup") : ""}`, label, activeLimit, member.requests, member.errors,
|
const row = el("tr"); if (vhostDisabled) row.classList.add("pool-vhost-disabled"); const poolDomain = status.backend_pool_domains?.[pool.id]; const poolLabel = poolDomain ? `${pool.id} (${poolDomain})` : pool.id; const cells = [poolLabel, `${member.id}${member.backup ? " / " + t("vhBackup") : ""}`, label, activeLimit, member.requests, member.errors,
|
||||||
member.ewma_latency_ms > 0 ? `${member.ewma_latency_ms.toFixed(1)} ms` : "-", `${rateBytes(memberTraffic)}/s`, lastFailure, lastRecovery];
|
member.ewma_latency_ms > 0 ? `${member.ewma_latency_ms.toFixed(1)} ms` : "-", `${rateBytes(memberTraffic)}/s`, member.upstream_client_generation ?? "-", member.upstream_client_generation_requests ?? "-", generationAgeText, member.upstream_client_rotations_total ?? "-", lastFailure, lastRecovery];
|
||||||
cells.forEach((value, index) => { const cell = el("td", String(value ?? "-")); cell.title = index === 2 ? (vhostDisabled ? t("vhDisabled") : `${label} · ${healthDetail}`) : index === 8 ? (member.last_failure_detail || lastFailure) : String(value ?? "-"); if (index === 2 && !vhostDisabled) cell.className = member.status === "down" ? "status-error" : member.status === "up" ? "status-good" : ""; if (index === 8 && member.last_failure_at_ms) cell.classList.add("backend-last-failure"); row.append(cell); }); rows.push(row);
|
cells.forEach((value, index) => { const cell = el("td", String(value ?? "-")); cell.title = index === 2 ? (vhostDisabled ? t("vhDisabled") : `${label} · ${healthDetail}`) : index === 12 ? (member.last_failure_detail || lastFailure) : String(value ?? "-"); if (index === 2 && !vhostDisabled) cell.className = member.status === "down" ? "status-error" : member.status === "up" ? "status-good" : ""; if (index === 12 && member.last_failure_at_ms) cell.classList.add("backend-last-failure"); row.append(cell); }); rows.push(row);
|
||||||
if (!vhostDisabled && member.status === "up") up++; active += Number(member.active) || 0; requests += Number(member.requests) || 0; errors += Number(member.errors) || 0; traffic += memberTraffic;
|
if (!vhostDisabled && member.status === "up") up++; active += Number(member.active) || 0; requests += Number(member.requests) || 0; errors += Number(member.errors) || 0; traffic += memberTraffic;
|
||||||
const latency = Number(member.ewma_latency_ms || member.latency_ms) || 0; if (latency > 0) { const weight = Math.max(1, Number(member.requests) || 1); weightedLatency += latency * weight; latencyWeight += weight; }
|
const latency = Number(member.ewma_latency_ms || member.latency_ms) || 0; if (latency > 0) { const weight = Math.max(1, Number(member.requests) || 1); weightedLatency += latency * weight; latencyWeight += weight; }
|
||||||
}
|
}
|
||||||
|
|||||||
+19
-1
@@ -54,6 +54,16 @@ pub struct Keepalive {
|
|||||||
pub idle_timeout_seconds: u64,
|
pub idle_timeout_seconds: u64,
|
||||||
pub max_idle_per_host: usize,
|
pub max_idle_per_host: usize,
|
||||||
pub tcp_keepalive_seconds: u64,
|
pub tcp_keepalive_seconds: u64,
|
||||||
|
/// Rebuild a backend Hyper client after this many requests. The counter is
|
||||||
|
/// per backend/client generation, not per TCP connection. Zero disables
|
||||||
|
/// request-count based recycling.
|
||||||
|
pub pool_recycle_requests: u64,
|
||||||
|
/// Maximum age of one backend Hyper client generation. Zero disables
|
||||||
|
/// time-based recycling.
|
||||||
|
pub pool_recycle_seconds: u64,
|
||||||
|
/// Bound Hyper's adaptive HTTP/1 read buffer per connection. Hyper requires
|
||||||
|
/// at least 8192 bytes. This affects upstream HTTP/1 only.
|
||||||
|
pub http1_max_buffer_bytes: usize,
|
||||||
}
|
}
|
||||||
impl Default for Keepalive {
|
impl Default for Keepalive {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
@@ -62,6 +72,9 @@ impl Default for Keepalive {
|
|||||||
idle_timeout_seconds: 30,
|
idle_timeout_seconds: 30,
|
||||||
max_idle_per_host: 4,
|
max_idle_per_host: 4,
|
||||||
tcp_keepalive_seconds: 30,
|
tcp_keepalive_seconds: 30,
|
||||||
|
pool_recycle_requests: 25_000,
|
||||||
|
pool_recycle_seconds: 3_600,
|
||||||
|
http1_max_buffer_bytes: 131_072,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -255,7 +268,12 @@ impl Settings {
|
|||||||
ensure!(
|
ensure!(
|
||||||
(1..=3600).contains(&k.idle_timeout_seconds)
|
(1..=3600).contains(&k.idle_timeout_seconds)
|
||||||
&& (1..=3600).contains(&k.tcp_keepalive_seconds)
|
&& (1..=3600).contains(&k.tcp_keepalive_seconds)
|
||||||
&& (1..=64).contains(&k.max_idle_per_host),
|
&& (1..=64).contains(&k.max_idle_per_host)
|
||||||
|
&& (k.pool_recycle_requests == 0
|
||||||
|
|| (1_000..=10_000_000).contains(&k.pool_recycle_requests))
|
||||||
|
&& (k.pool_recycle_seconds == 0
|
||||||
|
|| (60..=604_800).contains(&k.pool_recycle_seconds))
|
||||||
|
&& (8_192..=1_048_576).contains(&k.http1_max_buffer_bytes),
|
||||||
"invalid keepalive limits"
|
"invalid keepalive limits"
|
||||||
);
|
);
|
||||||
ensure!(
|
ensure!(
|
||||||
|
|||||||
@@ -61,6 +61,23 @@ impl Pool {
|
|||||||
"traffic_bytes_per_second".into(),
|
"traffic_bytes_per_second".into(),
|
||||||
json!(m.state.traffic_rate()),
|
json!(m.state.traffic_rate()),
|
||||||
);
|
);
|
||||||
|
let client_rotation = m.backend.client.rotation_stats();
|
||||||
|
item.insert(
|
||||||
|
"upstream_client_generation".into(),
|
||||||
|
json!(client_rotation.generation),
|
||||||
|
);
|
||||||
|
item.insert(
|
||||||
|
"upstream_client_generation_requests".into(),
|
||||||
|
json!(client_rotation.generation_requests),
|
||||||
|
);
|
||||||
|
item.insert(
|
||||||
|
"upstream_client_generation_age_seconds".into(),
|
||||||
|
json!(client_rotation.generation_age_seconds),
|
||||||
|
);
|
||||||
|
item.insert(
|
||||||
|
"upstream_client_rotations_total".into(),
|
||||||
|
json!(client_rotation.rotations),
|
||||||
|
);
|
||||||
item.insert("latency_ms".into(), json!(h.latency_us as f64 / 1000.0));
|
item.insert("latency_ms".into(), json!(h.latency_us as f64 / 1000.0));
|
||||||
item.insert("ewma_latency_ms".into(), json!(h.ewma_us as f64 / 1000.0));
|
item.insert("ewma_latency_ms".into(), json!(h.ewma_us as f64 / 1000.0));
|
||||||
item.insert("last_probe_ms".into(), json!(h.last_probe_ms));
|
item.insert("last_probe_ms".into(), json!(h.last_probe_ms));
|
||||||
|
|||||||
@@ -72,6 +72,30 @@ fn legacy_settings_without_passive_health_default_to_off() {
|
|||||||
assert!(parsed.retry.retry_connect_errors);
|
assert!(parsed.retry.retry_connect_errors);
|
||||||
assert!(parsed.retry.retry_timeouts);
|
assert!(parsed.retry.retry_timeouts);
|
||||||
assert_eq!(parsed.retry.retry_statuses, vec![502, 503, 504]);
|
assert_eq!(parsed.retry.retry_statuses, vec![502, 503, 504]);
|
||||||
|
assert_eq!(parsed.keepalive.pool_recycle_requests, 25_000);
|
||||||
|
assert_eq!(parsed.keepalive.pool_recycle_seconds, 3_600);
|
||||||
|
assert_eq!(parsed.keepalive.http1_max_buffer_bytes, 131_072);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn upstream_pool_recycle_limits_are_bounded_and_can_be_disabled() {
|
||||||
|
let mut settings = Settings::default();
|
||||||
|
assert!(settings.validate().is_ok());
|
||||||
|
|
||||||
|
settings.keepalive.pool_recycle_requests = 0;
|
||||||
|
settings.keepalive.pool_recycle_seconds = 0;
|
||||||
|
assert!(settings.validate().is_ok());
|
||||||
|
|
||||||
|
settings.keepalive.pool_recycle_requests = 999;
|
||||||
|
assert!(settings.validate().is_err());
|
||||||
|
settings.keepalive.pool_recycle_requests = 1_000;
|
||||||
|
settings.keepalive.pool_recycle_seconds = 59;
|
||||||
|
assert!(settings.validate().is_err());
|
||||||
|
settings.keepalive.pool_recycle_seconds = 60;
|
||||||
|
settings.keepalive.http1_max_buffer_bytes = 8_191;
|
||||||
|
assert!(settings.validate().is_err());
|
||||||
|
settings.keepalive.http1_max_buffer_bytes = 8_192;
|
||||||
|
assert!(settings.validate().is_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ use zeroize::Zeroizing;
|
|||||||
#[command(
|
#[command(
|
||||||
name = "rust-proxy",
|
name = "rust-proxy",
|
||||||
version,
|
version,
|
||||||
about = "RustProxy - independent Rust reverse proxy and static Web Server 0.25.5"
|
about = "RustProxy - independent Rust reverse proxy and static Web Server 0.25.6"
|
||||||
)]
|
)]
|
||||||
struct Cli {
|
struct Cli {
|
||||||
#[arg(
|
#[arg(
|
||||||
|
|||||||
+1
-1
@@ -239,7 +239,7 @@ async fn live_logs_command(dir: PathBuf, addr: SocketAddr) -> Result<()> {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
let interactive = io::stdin().is_terminal() && io::stdout().is_terminal();
|
let interactive = io::stdin().is_terminal() && io::stdout().is_terminal();
|
||||||
println!("RustProxy live logs 0.25.5 - all vhosts. Type 'help' for interactive filters; Ctrl-C or 'quit' exits.");
|
println!("RustProxy live logs 0.25.6 - all vhosts. Type 'help' for interactive filters; Ctrl-C or 'quit' exits.");
|
||||||
if interactive { print!("> "); io::stdout().flush()?; }
|
if interactive { print!("> "); io::stdout().flush()?; }
|
||||||
let mut filters = LiveLogFilters::default();
|
let mut filters = LiveLogFilters::default();
|
||||||
let mut history = std::collections::BTreeMap::<u64, serde_json::Value>::new();
|
let mut history = std::collections::BTreeMap::<u64, serde_json::Value>::new();
|
||||||
|
|||||||
+9
-126
@@ -1,23 +1,16 @@
|
|||||||
//! Per-backend connection pools and connect-time DNS validation.
|
//! Per-backend connection pools and connect-time DNS validation.
|
||||||
//! No HTTP caller can supply a destination. DNS answers are validated once and
|
//! No HTTP caller can supply a destination. DNS answers are validated once and
|
||||||
//! passed directly to HttpConnector; there is no second unvalidated lookup.
|
//! passed directly to HttpConnector; there is no second unvalidated lookup.
|
||||||
use crate::config::{ip_policy, Backend, UpstreamProtocol};
|
use crate::config::{ip_policy, Backend};
|
||||||
use anyhow::{ensure, Context, Result};
|
use anyhow::{ensure, Context, Result};
|
||||||
use axum::body::Body;
|
|
||||||
use http::Uri;
|
use http::Uri;
|
||||||
use hyper_rustls::{HttpsConnector, HttpsConnectorBuilder};
|
use hyper_rustls::HttpsConnector;
|
||||||
use hyper_util::{
|
use hyper_util::client::legacy::connect::{dns::Name, HttpConnector};
|
||||||
client::legacy::{
|
|
||||||
connect::{dns::Name, HttpConnector},
|
|
||||||
Client,
|
|
||||||
},
|
|
||||||
rt::{TokioExecutor, TokioTimer},
|
|
||||||
};
|
|
||||||
use ipnet::IpNet;
|
use ipnet::IpNet;
|
||||||
use rustls::{
|
use rustls::{
|
||||||
client::danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier},
|
client::danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier},
|
||||||
pki_types::{CertificateDer, ServerName, UnixTime},
|
pki_types::{CertificateDer, ServerName, UnixTime},
|
||||||
ClientConfig, DigitallySignedStruct, RootCertStore, SignatureScheme,
|
DigitallySignedStruct, RootCertStore, SignatureScheme,
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
future::Future,
|
future::Future,
|
||||||
@@ -36,7 +29,11 @@ const CONNECT_TIMEOUT: Duration = Duration::from_secs(10);
|
|||||||
const MAX_DNS_ANSWERS: usize = 32;
|
const MAX_DNS_ANSWERS: usize = 32;
|
||||||
static DNS_SLOTS: OnceLock<Arc<Semaphore>> = OnceLock::new();
|
static DNS_SLOTS: OnceLock<Arc<Semaphore>> = OnceLock::new();
|
||||||
pub type BoxError = Box<dyn std::error::Error + Send + Sync>;
|
pub type BoxError = Box<dyn std::error::Error + Send + Sync>;
|
||||||
pub type ProxyClient = Client<TimedConnector, Body>;
|
|
||||||
|
mod client;
|
||||||
|
pub use client::{
|
||||||
|
client, client_with_keepalive, client_with_timeout, ClientRotationStats, ProxyClient,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
pub struct AddressPolicy {
|
pub struct AddressPolicy {
|
||||||
@@ -297,120 +294,6 @@ impl ServerCertVerifier for BackendCertificateVerificationDisabled {
|
|||||||
self.supported_schemes.clone()
|
self.supported_schemes.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn client(backend: &Backend, policy: AddressPolicy, websocket: bool) -> Result<ProxyClient> {
|
|
||||||
client_with_keepalive(
|
|
||||||
backend,
|
|
||||||
policy,
|
|
||||||
websocket,
|
|
||||||
&crate::balance::Keepalive::default(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
pub fn client_with_keepalive(
|
|
||||||
backend: &Backend,
|
|
||||||
policy: AddressPolicy,
|
|
||||||
websocket: bool,
|
|
||||||
keepalive: &crate::balance::Keepalive,
|
|
||||||
) -> Result<ProxyClient> {
|
|
||||||
client_with_timeout(backend, policy, websocket, keepalive, CONNECT_TIMEOUT)
|
|
||||||
}
|
|
||||||
pub fn client_with_timeout(
|
|
||||||
backend: &Backend,
|
|
||||||
policy: AddressPolicy,
|
|
||||||
websocket: bool,
|
|
||||||
keepalive: &crate::balance::Keepalive,
|
|
||||||
timeout: Duration,
|
|
||||||
) -> Result<ProxyClient> {
|
|
||||||
// HTTPS "http2" prefers h2 but always offers HTTP/1.1. Cleartext http2 remains
|
|
||||||
// explicit h2c prior knowledge; never replay a failed TLS request to downgrade.
|
|
||||||
let is_https = url::Url::parse(&backend.url)?.scheme() == "https";
|
|
||||||
let protocol = if websocket {
|
|
||||||
UpstreamProtocol::Http1
|
|
||||||
} else if backend.protocol == UpstreamProtocol::Http2 && is_https {
|
|
||||||
UpstreamProtocol::Auto
|
|
||||||
} else {
|
|
||||||
backend.protocol
|
|
||||||
};
|
|
||||||
let provider = Arc::new(rustls::crypto::ring::default_provider());
|
|
||||||
let trust_roots = if backend.tls_verify {
|
|
||||||
roots(backend)?
|
|
||||||
} else {
|
|
||||||
// tls_ca_pem is intentionally ignored when verification is disabled.
|
|
||||||
public_roots()
|
|
||||||
};
|
|
||||||
let mut config = ClientConfig::builder_with_provider(provider.clone())
|
|
||||||
.with_safe_default_protocol_versions()?
|
|
||||||
.with_root_certificates(trust_roots)
|
|
||||||
.with_no_client_auth();
|
|
||||||
if !backend.tls_verify {
|
|
||||||
let supported_schemes = provider
|
|
||||||
.signature_verification_algorithms
|
|
||||||
.supported_schemes();
|
|
||||||
config.dangerous().set_certificate_verifier(Arc::new(
|
|
||||||
BackendCertificateVerificationDisabled { supported_schemes },
|
|
||||||
));
|
|
||||||
}
|
|
||||||
let connect_host = if backend.tls_server_name.is_some() {
|
|
||||||
Some(
|
|
||||||
url::Url::parse(&backend.url)?
|
|
||||||
.host_str()
|
|
||||||
.context("backend host missing")?
|
|
||||||
.trim_start_matches('[')
|
|
||||||
.trim_end_matches(']')
|
|
||||||
.to_owned(),
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
let mut http = HttpConnector::new_with_resolver(GuardedResolver {
|
|
||||||
policy: policy.clone(),
|
|
||||||
connect_host,
|
|
||||||
});
|
|
||||||
http.enforce_http(false);
|
|
||||||
http.set_connect_timeout(Some(timeout));
|
|
||||||
http.set_nodelay(true);
|
|
||||||
http.set_keepalive(
|
|
||||||
keepalive
|
|
||||||
.enabled
|
|
||||||
.then_some(Duration::from_secs(keepalive.tcp_keepalive_seconds)),
|
|
||||||
);
|
|
||||||
let builder = HttpsConnectorBuilder::new()
|
|
||||||
.with_tls_config(config)
|
|
||||||
.https_or_http();
|
|
||||||
let inner = match protocol {
|
|
||||||
UpstreamProtocol::Http1 => builder.enable_http1().wrap_connector(http),
|
|
||||||
UpstreamProtocol::Http2 => builder.enable_http2().wrap_connector(http),
|
|
||||||
UpstreamProtocol::Auto => builder.enable_http1().enable_http2().wrap_connector(http),
|
|
||||||
};
|
|
||||||
let mut builder = Client::builder(TokioExecutor::new());
|
|
||||||
builder
|
|
||||||
// Header field names are case-insensitive by HTTP specification, but some
|
|
||||||
// legacy/custom origins parse HTTP/1 request headers case-sensitively.
|
|
||||||
// Hyper writes lowercase names by default; title-case them on the wire for
|
|
||||||
// broad origin compatibility. This setting does not affect HTTP/2.
|
|
||||||
.http1_title_case_headers(true)
|
|
||||||
.pool_timer(TokioTimer::new())
|
|
||||||
.pool_idle_timeout(Duration::from_secs(keepalive.idle_timeout_seconds))
|
|
||||||
.pool_max_idle_per_host(if keepalive.enabled {
|
|
||||||
keepalive.max_idle_per_host
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
})
|
|
||||||
.retry_canceled_requests(false)
|
|
||||||
.http2_only(protocol == UpstreamProtocol::Http2)
|
|
||||||
.timer(TokioTimer::new())
|
|
||||||
.http2_keep_alive_interval(
|
|
||||||
keepalive
|
|
||||||
.enabled
|
|
||||||
.then_some(Duration::from_secs(keepalive.tcp_keepalive_seconds)),
|
|
||||||
)
|
|
||||||
.http2_keep_alive_timeout(Duration::from_secs(10))
|
|
||||||
.http2_keep_alive_while_idle(false);
|
|
||||||
Ok(builder.build(TimedConnector {
|
|
||||||
inner,
|
|
||||||
policy,
|
|
||||||
timeout,
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
/// A bounded raw TCP liveness check, using the same configured-origin address
|
/// A bounded raw TCP liveness check, using the same configured-origin address
|
||||||
/// policy as normal requests. Every DNS answer is checked before any connection.
|
/// policy as normal requests. Every DNS answer is checked before any connection.
|
||||||
pub async fn tcp_probe(origin: &str, policy: &AddressPolicy) -> Result<()> {
|
pub async fn tcp_probe(origin: &str, policy: &AddressPolicy) -> Result<()> {
|
||||||
|
|||||||
@@ -0,0 +1,325 @@
|
|||||||
|
use super::{
|
||||||
|
public_roots, roots, AddressPolicy, BackendCertificateVerificationDisabled, TimedConnector,
|
||||||
|
CONNECT_TIMEOUT,
|
||||||
|
};
|
||||||
|
use crate::config::{Backend, UpstreamProtocol};
|
||||||
|
use anyhow::{Context, Result};
|
||||||
|
use arc_swap::ArcSwap;
|
||||||
|
use axum::body::Body;
|
||||||
|
use http::{Request, Response};
|
||||||
|
use hyper::body::Incoming;
|
||||||
|
use hyper_rustls::HttpsConnectorBuilder;
|
||||||
|
use hyper_util::{
|
||||||
|
client::legacy::{Client, Error as ClientError},
|
||||||
|
rt::{TokioExecutor, TokioTimer},
|
||||||
|
};
|
||||||
|
use rustls::ClientConfig;
|
||||||
|
use std::{
|
||||||
|
sync::{
|
||||||
|
atomic::{AtomicBool, AtomicU64, Ordering},
|
||||||
|
Arc, OnceLock,
|
||||||
|
},
|
||||||
|
time::{Duration, Instant},
|
||||||
|
};
|
||||||
|
|
||||||
|
static MONOTONIC_START: OnceLock<Instant> = OnceLock::new();
|
||||||
|
type RawProxyClient = Client<super::TimedConnector, Body>;
|
||||||
|
|
||||||
|
fn monotonic_millis() -> u64 {
|
||||||
|
MONOTONIC_START
|
||||||
|
.get_or_init(Instant::now)
|
||||||
|
.elapsed()
|
||||||
|
.as_millis()
|
||||||
|
.min(u64::MAX as u128) as u64
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct ClientFactory {
|
||||||
|
backend: Backend,
|
||||||
|
policy: AddressPolicy,
|
||||||
|
websocket: bool,
|
||||||
|
keepalive: crate::balance::Keepalive,
|
||||||
|
timeout: Duration,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct RotatingClient {
|
||||||
|
current: ArcSwap<RawProxyClient>,
|
||||||
|
factory: ClientFactory,
|
||||||
|
generation: AtomicU64,
|
||||||
|
generation_requests: AtomicU64,
|
||||||
|
generation_started_ms: AtomicU64,
|
||||||
|
rotations: AtomicU64,
|
||||||
|
rotating: AtomicBool,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Backend HTTP client with bounded generation lifetime.
|
||||||
|
///
|
||||||
|
/// Hyper reuses a client/pool for efficiency. Under sustained traffic that also
|
||||||
|
/// makes connection/TLS/buffer high-water allocations live as long as the
|
||||||
|
/// compiled vhost snapshot. Recycling only this client generation bounds that
|
||||||
|
/// lifetime without reloading the vhost or touching cache/configuration state.
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct ProxyClient {
|
||||||
|
inner: Arc<RotatingClient>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct ClientRotationStats {
|
||||||
|
pub generation: u64,
|
||||||
|
pub generation_requests: u64,
|
||||||
|
pub generation_age_seconds: u64,
|
||||||
|
pub rotations: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Debug for ProxyClient {
|
||||||
|
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
formatter
|
||||||
|
.debug_struct("ProxyClient")
|
||||||
|
.field("rotation", &self.rotation_stats())
|
||||||
|
.finish_non_exhaustive()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ProxyClient {
|
||||||
|
fn new(current: RawProxyClient, factory: ClientFactory) -> Self {
|
||||||
|
Self {
|
||||||
|
inner: Arc::new(RotatingClient {
|
||||||
|
current: ArcSwap::from_pointee(current),
|
||||||
|
factory,
|
||||||
|
generation: AtomicU64::new(0),
|
||||||
|
generation_requests: AtomicU64::new(0),
|
||||||
|
generation_started_ms: AtomicU64::new(monotonic_millis()),
|
||||||
|
rotations: AtomicU64::new(0),
|
||||||
|
rotating: AtomicBool::new(false),
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn request(&self, request: Request<Body>) -> Result<Response<Incoming>, ClientError> {
|
||||||
|
let client = self.inner.client_for_request();
|
||||||
|
client.request(request).await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rotation_stats(&self) -> ClientRotationStats {
|
||||||
|
self.inner.stats()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RotatingClient {
|
||||||
|
fn stats(&self) -> ClientRotationStats {
|
||||||
|
let now = monotonic_millis();
|
||||||
|
ClientRotationStats {
|
||||||
|
generation: self.generation.load(Ordering::Relaxed),
|
||||||
|
generation_requests: self.generation_requests.load(Ordering::Relaxed),
|
||||||
|
generation_age_seconds: now
|
||||||
|
.saturating_sub(self.generation_started_ms.load(Ordering::Relaxed))
|
||||||
|
/ 1_000,
|
||||||
|
rotations: self.rotations.load(Ordering::Relaxed),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn client_for_request(&self) -> Arc<RawProxyClient> {
|
||||||
|
let observed_generation = self.generation.load(Ordering::Acquire);
|
||||||
|
let requests = self
|
||||||
|
.generation_requests
|
||||||
|
.fetch_add(1, Ordering::Relaxed)
|
||||||
|
.saturating_add(1);
|
||||||
|
let now = monotonic_millis();
|
||||||
|
let age_ms = now.saturating_sub(self.generation_started_ms.load(Ordering::Relaxed));
|
||||||
|
let request_due = self.factory.keepalive.pool_recycle_requests > 0
|
||||||
|
&& requests > self.factory.keepalive.pool_recycle_requests;
|
||||||
|
let age_due = self.factory.keepalive.pool_recycle_seconds > 0
|
||||||
|
&& age_ms
|
||||||
|
>= self
|
||||||
|
.factory
|
||||||
|
.keepalive
|
||||||
|
.pool_recycle_seconds
|
||||||
|
.saturating_mul(1_000);
|
||||||
|
if request_due || age_due {
|
||||||
|
self.rotate(observed_generation, if request_due { "requests" } else { "age" });
|
||||||
|
}
|
||||||
|
self.current.load_full()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rotate(&self, observed_generation: u64, reason: &'static str) {
|
||||||
|
if self.generation.load(Ordering::Acquire) != observed_generation
|
||||||
|
|| self
|
||||||
|
.rotating
|
||||||
|
.compare_exchange(false, true, Ordering::AcqRel, Ordering::Acquire)
|
||||||
|
.is_err()
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if self.generation.load(Ordering::Acquire) != observed_generation {
|
||||||
|
self.rotating.store(false, Ordering::Release);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
match build_raw_client(&self.factory) {
|
||||||
|
Ok(client) => {
|
||||||
|
let next_generation = observed_generation.saturating_add(1);
|
||||||
|
self.current.store(Arc::new(client));
|
||||||
|
// The request that triggered the swap is sent through the new
|
||||||
|
// generation after rotate() returns, so count it there.
|
||||||
|
self.generation_requests.store(1, Ordering::Relaxed);
|
||||||
|
self.generation_started_ms
|
||||||
|
.store(monotonic_millis(), Ordering::Relaxed);
|
||||||
|
self.generation.store(next_generation, Ordering::Release);
|
||||||
|
self.rotations.fetch_add(1, Ordering::Relaxed);
|
||||||
|
tracing::debug!(
|
||||||
|
backend = %self.factory.backend.id,
|
||||||
|
generation = next_generation,
|
||||||
|
reason,
|
||||||
|
"recycled upstream client pool"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Err(error) => {
|
||||||
|
// The same immutable settings built the current client. If a
|
||||||
|
// future dependency makes rebuilding fail, keep serving through
|
||||||
|
// the current generation and retry only after another interval.
|
||||||
|
self.generation_requests.store(0, Ordering::Relaxed);
|
||||||
|
self.generation_started_ms
|
||||||
|
.store(monotonic_millis(), Ordering::Relaxed);
|
||||||
|
tracing::warn!(
|
||||||
|
backend = %self.factory.backend.id,
|
||||||
|
error = %error,
|
||||||
|
"could not recycle upstream client pool; keeping current generation"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.rotating.store(false, Ordering::Release);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn client(backend: &Backend, policy: AddressPolicy, websocket: bool) -> Result<ProxyClient> {
|
||||||
|
client_with_keepalive(
|
||||||
|
backend,
|
||||||
|
policy,
|
||||||
|
websocket,
|
||||||
|
&crate::balance::Keepalive::default(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn client_with_keepalive(
|
||||||
|
backend: &Backend,
|
||||||
|
policy: AddressPolicy,
|
||||||
|
websocket: bool,
|
||||||
|
keepalive: &crate::balance::Keepalive,
|
||||||
|
) -> Result<ProxyClient> {
|
||||||
|
client_with_timeout(backend, policy, websocket, keepalive, CONNECT_TIMEOUT)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn client_with_timeout(
|
||||||
|
backend: &Backend,
|
||||||
|
policy: AddressPolicy,
|
||||||
|
websocket: bool,
|
||||||
|
keepalive: &crate::balance::Keepalive,
|
||||||
|
timeout: Duration,
|
||||||
|
) -> Result<ProxyClient> {
|
||||||
|
let factory = ClientFactory {
|
||||||
|
backend: backend.clone(),
|
||||||
|
policy,
|
||||||
|
websocket,
|
||||||
|
keepalive: keepalive.clone(),
|
||||||
|
timeout,
|
||||||
|
};
|
||||||
|
let current = build_raw_client(&factory)?;
|
||||||
|
Ok(ProxyClient::new(current, factory))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_raw_client(factory: &ClientFactory) -> Result<RawProxyClient> {
|
||||||
|
let backend = &factory.backend;
|
||||||
|
let policy = &factory.policy;
|
||||||
|
let websocket = factory.websocket;
|
||||||
|
let keepalive = &factory.keepalive;
|
||||||
|
let timeout = factory.timeout;
|
||||||
|
let is_https = url::Url::parse(&backend.url)?.scheme() == "https";
|
||||||
|
let protocol = if websocket {
|
||||||
|
UpstreamProtocol::Http1
|
||||||
|
} else if backend.protocol == UpstreamProtocol::Http2 && is_https {
|
||||||
|
UpstreamProtocol::Auto
|
||||||
|
} else {
|
||||||
|
backend.protocol
|
||||||
|
};
|
||||||
|
let provider = Arc::new(rustls::crypto::ring::default_provider());
|
||||||
|
let trust_roots = if backend.tls_verify {
|
||||||
|
roots(backend)?
|
||||||
|
} else {
|
||||||
|
public_roots()
|
||||||
|
};
|
||||||
|
let mut config = ClientConfig::builder_with_provider(provider.clone())
|
||||||
|
.with_safe_default_protocol_versions()?
|
||||||
|
.with_root_certificates(trust_roots)
|
||||||
|
.with_no_client_auth();
|
||||||
|
if !backend.tls_verify {
|
||||||
|
let supported_schemes = provider
|
||||||
|
.signature_verification_algorithms
|
||||||
|
.supported_schemes();
|
||||||
|
config.dangerous().set_certificate_verifier(Arc::new(
|
||||||
|
BackendCertificateVerificationDisabled { supported_schemes },
|
||||||
|
));
|
||||||
|
}
|
||||||
|
let connect_host = if backend.tls_server_name.is_some() {
|
||||||
|
Some(
|
||||||
|
url::Url::parse(&backend.url)?
|
||||||
|
.host_str()
|
||||||
|
.context("backend host missing")?
|
||||||
|
.trim_start_matches('[')
|
||||||
|
.trim_end_matches(']')
|
||||||
|
.to_owned(),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
let mut http = hyper_util::client::legacy::connect::HttpConnector::new_with_resolver(
|
||||||
|
super::GuardedResolver {
|
||||||
|
policy: policy.clone(),
|
||||||
|
connect_host,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
http.enforce_http(false);
|
||||||
|
http.set_connect_timeout(Some(timeout));
|
||||||
|
http.set_nodelay(true);
|
||||||
|
http.set_keepalive(
|
||||||
|
keepalive
|
||||||
|
.enabled
|
||||||
|
.then_some(Duration::from_secs(keepalive.tcp_keepalive_seconds)),
|
||||||
|
);
|
||||||
|
let builder = HttpsConnectorBuilder::new()
|
||||||
|
.with_tls_config(config)
|
||||||
|
.https_or_http();
|
||||||
|
let inner = match protocol {
|
||||||
|
UpstreamProtocol::Http1 => builder.enable_http1().wrap_connector(http),
|
||||||
|
UpstreamProtocol::Http2 => builder.enable_http2().wrap_connector(http),
|
||||||
|
UpstreamProtocol::Auto => builder.enable_http1().enable_http2().wrap_connector(http),
|
||||||
|
};
|
||||||
|
let mut builder = Client::builder(TokioExecutor::new());
|
||||||
|
builder
|
||||||
|
.http1_title_case_headers(true)
|
||||||
|
.http1_max_buf_size(keepalive.http1_max_buffer_bytes)
|
||||||
|
.pool_timer(TokioTimer::new())
|
||||||
|
.pool_idle_timeout(Duration::from_secs(keepalive.idle_timeout_seconds))
|
||||||
|
.pool_max_idle_per_host(if keepalive.enabled {
|
||||||
|
keepalive.max_idle_per_host
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
})
|
||||||
|
.retry_canceled_requests(false)
|
||||||
|
.http2_only(protocol == UpstreamProtocol::Http2)
|
||||||
|
.timer(TokioTimer::new())
|
||||||
|
.http2_keep_alive_interval(
|
||||||
|
keepalive
|
||||||
|
.enabled
|
||||||
|
.then_some(Duration::from_secs(keepalive.tcp_keepalive_seconds)),
|
||||||
|
)
|
||||||
|
.http2_keep_alive_timeout(Duration::from_secs(10))
|
||||||
|
.http2_keep_alive_while_idle(false);
|
||||||
|
Ok(builder.build(TimedConnector {
|
||||||
|
inner,
|
||||||
|
policy: policy.clone(),
|
||||||
|
timeout,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
include!("client_tests.rs");
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
fn backend(id: &str, port: u16) -> Backend {
|
||||||
|
serde_json::from_value(serde_json::json!({
|
||||||
|
"id": id,
|
||||||
|
"url": format!("http://127.0.0.1:{port}"),
|
||||||
|
"protocol": "http1",
|
||||||
|
"allow_private": true
|
||||||
|
}))
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn generation_recycles_after_request_budget() {
|
||||||
|
let backend = backend("rotation-test", 18081);
|
||||||
|
let mut keepalive = crate::balance::Keepalive::default();
|
||||||
|
keepalive.pool_recycle_requests = 2;
|
||||||
|
keepalive.pool_recycle_seconds = 0;
|
||||||
|
let client = client_with_keepalive(
|
||||||
|
&backend,
|
||||||
|
AddressPolicy::new(&backend).unwrap(),
|
||||||
|
false,
|
||||||
|
&keepalive,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
client.inner.client_for_request();
|
||||||
|
client.inner.client_for_request();
|
||||||
|
assert_eq!(client.rotation_stats().rotations, 0);
|
||||||
|
client.inner.client_for_request();
|
||||||
|
let stats = client.rotation_stats();
|
||||||
|
assert_eq!(stats.rotations, 1);
|
||||||
|
assert_eq!(stats.generation, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn generation_recycling_can_be_disabled() {
|
||||||
|
let backend = backend("rotation-off", 18082);
|
||||||
|
let mut keepalive = crate::balance::Keepalive::default();
|
||||||
|
keepalive.pool_recycle_requests = 0;
|
||||||
|
keepalive.pool_recycle_seconds = 0;
|
||||||
|
let client = client_with_keepalive(
|
||||||
|
&backend,
|
||||||
|
AddressPolicy::new(&backend).unwrap(),
|
||||||
|
false,
|
||||||
|
&keepalive,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
for _ in 0..10 {
|
||||||
|
client.inner.client_for_request();
|
||||||
|
}
|
||||||
|
assert_eq!(client.rotation_stats().rotations, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -4,7 +4,7 @@ mod tests {
|
|||||||
use http::{Request, Response, Version};
|
use http::{Request, Response, Version};
|
||||||
use http_body_util::{BodyExt, Full};
|
use http_body_util::{BodyExt, Full};
|
||||||
use hyper::service::service_fn;
|
use hyper::service::service_fn;
|
||||||
use hyper_util::rt::TokioIo;
|
use hyper_util::rt::{TokioExecutor, TokioIo};
|
||||||
use std::convert::Infallible;
|
use std::convert::Infallible;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -156,7 +156,7 @@ pub(super) fn fastcgi_params(
|
|||||||
}
|
}
|
||||||
params.insert("HTTPS".into(), if context.tls { "on" } else { "off" }.into());
|
params.insert("HTTPS".into(), if context.tls { "on" } else { "off" }.into());
|
||||||
params.insert("GATEWAY_INTERFACE".into(), "CGI/1.1".into());
|
params.insert("GATEWAY_INTERFACE".into(), "CGI/1.1".into());
|
||||||
params.insert("SERVER_SOFTWARE".into(), "RustProxy/0.25.5".into());
|
params.insert("SERVER_SOFTWARE".into(), "RustProxy/0.25.6".into());
|
||||||
params.insert("REDIRECT_STATUS".into(), "200".into());
|
params.insert("REDIRECT_STATUS".into(), "200".into());
|
||||||
if let Some(value) = headers.get(CONTENT_TYPE).and_then(|value| value.to_str().ok()) {
|
if let Some(value) = headers.get(CONTENT_TYPE).and_then(|value| value.to_str().ok()) {
|
||||||
params.insert("CONTENT_TYPE".into(), value.into());
|
params.insert("CONTENT_TYPE".into(), value.into());
|
||||||
|
|||||||
@@ -180,7 +180,7 @@ pub(super) fn directory_listing(path: &str, entries: &[DirectoryEntry]) -> Vec<u
|
|||||||
"<a class=\"{class}\" href=\"{href}\"><span class=\"type\">{type_label}</span><span class=\"name\">{label}{slash}</span><span class=\"kind\">{kind}</span></a>"
|
"<a class=\"{class}\" href=\"{href}\"><span class=\"type\">{type_label}</span><span class=\"name\">{label}{slash}</span><span class=\"kind\">{kind}</span></a>"
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
html.push_str(r#"</div></section><footer class="page-footer"><span>RustProxy <b>0.25.5</b></span><span>Web Server · Directory listing</span></footer></main></body></html>"#);
|
html.push_str(r#"</div></section><footer class="page-footer"><span>RustProxy <b>0.25.6</b></span><span>Web Server · Directory listing</span></footer></main></body></html>"#);
|
||||||
html.into_bytes()
|
html.into_bytes()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -202,7 +202,7 @@ async fn empty_index_can_go_directly_to_directory_listing() {
|
|||||||
let body = std::str::from_utf8(&body).unwrap();
|
let body = std::str::from_utf8(&body).unwrap();
|
||||||
assert!(body.contains("file.txt"));
|
assert!(body.contains("file.txt"));
|
||||||
assert!(body.contains("DIRECTORY LISTING"));
|
assert!(body.contains("DIRECTORY LISTING"));
|
||||||
assert!(body.contains("RustProxy <b>0.25.5</b>"));
|
assert!(body.contains("RustProxy <b>0.25.6</b>"));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
|||||||
Reference in new issue
Block a user