15 KiB
Verification report - RustProxy 0.25.2
Scope
RustProxy 0.25.2 is a focused live-backup, backup-symlink and resumed-admin-session hardening release on top of the 0.25.1 source tree. Web Services are independent configuration resources; vhosts and custom locations only choose a source type and reference a Web Service ID. The current development tree provides static GET/HEAD streaming, directory/index behavior, validators, single ranges, document-root confinement, ordered try_files, Web Service rewrites, a bounded migration-oriented .htaccess compatibility layer, expanded MIME policy, per-extension/MIME Cache-Control rules, fixed source headers, precompressed sidecars, forced-download extensions and optional bounded FastCGI/PHP-FPM. The Web Service editor is organized into General, Routing, .htaccess, MIME, Cache & headers, Delivery, PHP-FPM and Security tabs, with one-shot presets for Static/SPA/PHP/WordPress/Drupal/Laravel/Symfony/Joomla/PrestaShop/Downloads. Existing 0.25 work also includes repeatable directory listing, Web Server vhost-wide metrics, Logging sub-tabs, corrected structured-log source validation, bounded per-vhost Traffic analytics with effective-client-IP rankings/donut charts, User-Agent/optional-country logging, stable Web Service rendering after fast refreshes, generic/customizable 403 handling and automatic RSS relief for reclaimable allocator/HOT-cache memory. The /docs surface separates the Markdown Reader from API/OpenAPI and documents the implemented PHP-FPM runtime.
Source contracts reviewed
Config.web_servicesis a separate persisted collection; vhost/locationsourcedefaults to Reverse Proxy for old documents and Web Server stores onlyweb_service_id.- Full configuration compilation validates Web Service IDs, absolute/existing document roots, index names, duplicate IDs and every active Web Service reference. A pure static vhost does not require a backend pool; mixed Web Server and Reverse Proxy locations do.
- Web Server dispatch occurs after normal frontend routing, ACL and Basic/Tinyauth authorization and before backend selection/DNS/cache/upstream work. Static responses continue through the existing custom error-page, response-header/security, compression and transport pipeline.
- Static files use streamed Tokio file bodies with explicit lengths rather than whole-file buffering.
- Files support metadata-based ETag/Last-Modified, If-None-Match/If-Modified-Since, one Range/If-Range and 304/206/416 behavior.
- Directory requests redirect to a slash path, then search the optional ordered index list (which may be empty), then optionally render an HTML-escaped and URL-encoded RustProxy-styled listing without exposing filesystem paths.
- Root directory listing opens a fresh directory file description per request rather than a
dupsharing the persistent root descriptor offset; a regression test requests the same listing twice. Nested directories independently apply index lookup first and listing fallback only when no index exists. Generated listings sendCache-Control: no-store. - A directory with no matching index and directory listing disabled returns the built-in generic 403 page (or the configured vhost/global 403 replacement in the outer response pass), not a Web Server implementation-detail string. HEAD keeps an empty body.
- Web Services support up to 64 normalized MIME overrides, a validated fallback MIME header and an optional validated default
Cache-Controlheader. Static files remain backed by the filesystem/OS page cache; existing vhost/location response-header rules run later and can override the source-level cache policy. - Web Services additionally support ordered
ext:/mime:Cache-Control rules, validated fixed response headers, orderedtry_files, regex internal/redirect rewrites, precompressed.br/.gzsidecars and attachment extensions. Protected framing/transport headers cannot be overridden by the source header map. - Optional
.htaccesscompatibility compiles a bounded root/subdirectory set at Web Service Apply time rather than parsing per request. It supports common RewriteRule/RewriteCond front controllers, DirectoryIndex/Indexes, AddType, Header, Expires, PHP AddHandler and simple Require all granted/denied. Unsupported access/handler scopes fail closed,.ht*control files are never served, and PHP AddHandler requires PHP-FPM. - Web Service presets are UI-only generators: they populate ordinary configuration fields and do not persist a hidden CMS mode. ID/name/document root and PHP-FPM endpoint/tuning remain operator-owned. Optional hardening is persisted explicitly and defaults off for compatibility.
block_common_attacksrejects TRACE/CONNECT/TRACK, sensitive dot/control/backup paths and a bounded set of high-confidence exploit probes; it also suppresses FastCGIHTTP_PROXYderivation from the inboundProxyheader. It does not claim generic WAF/SQLi/XSS filtering.strip_unnecessary_headersremoves common source/PHP fingerprint headers after Web Service and.htaccessresponse handling while leaving the later vhost/location response-header pipeline authoritative.- Optional PHP handling executes configured extensions through a bounded FastCGI connector over Unix socket or loopback TCP. PHP concurrency uses a fixed semaphore without an unbounded wait queue, request/response bodies use bounded streaming, and connection failure cannot fall back to serving PHP source. Advanced configuration adds Authorization forwarding control, a streaming request-body ceiling, bounded CGI response headers/stderr, trusted custom FastCGI parameters and validated
PHP_VALUEoverrides that cannot replace core CGI/HTTP fields orPHP_ADMIN_VALUE. - Web Service symlink policy defaults to
deny/O_NOFOLLOW; Linux-onlyinside_rootverifies opened descriptors through/proc/self/fdagainst the canonical root. PHP-FPM is intentionally limited todenybecause the external worker reopensSCRIPT_FILENAME. - Routing rejects malformed/ambiguous encoded paths before filesystem lookup. Unix filesystem lookup walks from an opened root descriptor;
denyusesopenat+O_NOFOLLOW, while Linux-onlyinside_rootverifies every opened descriptor against the canonical root. PHP-FPM requiresdeny. The secure Web Server compile path remains Unix-only. - No second URL router, custom-error subsystem or object cache was introduced. Reverse Proxy remains the default source for existing configuration.
- Dashboard CRUD, source selectors, English/Polish strings and OpenAPI schemas expose the new model.
- Web Service index files are optional (0..16). An empty list skips index lookup, allowing directory-listing-only services without synthetic index names.
- Generated directory listings use a self-contained RustProxy panel-style layout (matching palette/typography, responsive light/dark treatment and RustProxy footer) while preserving HTML escaping, URL encoding and filesystem-path secrecy.
- Pure Web Server vhosts no longer present backend diagnostics as though an origin pool existed; their Backends summary identifies
Web Server, while mixed static/proxy vhosts retain backend diagnostics. - Status payloads expose fixed-cardinality per-vhost metrics independently of backend pools. The Vhosts dashboard uses those counters for Web Server-only request/active/error values, EWMA latency and byte-rate traffic while retaining backend health details for reverse-proxy sources.
- Logging settings are split into Outputs, JSON format and Error log sub-tabs inside one card, matching the Cache subsection layout.
route,cache_effective_enabledandtransform_effective_enabledare accepted by the same backend validator that saves custom JSON mappings, and the regression test validates then renders those fields. - Structured logging now exposes
user_agentandcountry. User-Agent capture defaults on; country capture defaults off and GeoIP resolution is skipped unless capture or an existing country ACL/rate-limit needs it. - 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. - 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.
- Web Service cards use only the shared
el(...)DOM helper; a regression contract rejects the previous undefinedtext(...)call that aborted list rendering. Authenticated-shell startup now verifies/api/auth/sessionfirst 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. - The Web Server UI module performs a catch-up render when it registers after
app.js; this closes the race where a very fast/api/configresponse could finish beforeweb-server.jsexisted and leave the Web Service list blank until a later render. - The Web Service editor now builds its configuration tabs with the same
vh-tabs+quietbutton pattern and active/ARIA state handling as the Vhost editor; the source contract also checks this shared modal-tab pattern and invalid-field navigation switches to the owning tab. - Static dispatch clones only
Method,HeaderMapandUribefore awaiting the filesystem source; it does not hold&Request<Body>across an await, keeping the Axum 0.8 fallback handler futureSend. This addresses the reportedHandler<_, _>/ E0277 failure at.fallback(forward). /docsis an authenticated documentation surface with a Markdown Reader, searchable embedded docs bundle and a separate API/OpenAPI tab. Reader Markdown files are directinclude_str!compiler inputs and no longer depend on a generatedOUT_DIR/docs-content.json, preventing clean/incremental builds from failing on a missing documentation artifact.- Documentation cleanup keeps README and the active ROADMAP current-only; operator release history, developer-level changelog history and completed roadmap milestones are separated into CHANGELOG/audit/archive documents.
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 and effective-client-IP view 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. ACL tests include encoded traversal/separator/malformed-encoding cases.
Rust-independent release checks additionally validate UI/JSON/language/source contracts and reproducible packaging.
Modular source-tree verification
python3 scripts/rust_module_contracts.py: PASS. Every repository.rsfile is at most 500 lines.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.- Oversized
app.js/vhosts.jssource is split while the public/assets/app.jsand/assets/vhosts.jsURLs remain stable; the Docker Agent is split into model/Docker/network/certificate/server/entry-point files. - Rust unit-test bodies are isolated under
tests.rs/tests/; implementation files contain only guarded test includes/declarations. - All
include!("*.rs")targets resolve, split fragments have balanced delimiters, and no fragment ends in a dangling Rust attribute or doc comment. - Regression guards cover the Web Server split errors previously observed around
#[derive],htaccess,server_protocolandanyhow::Context. - 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
| Check | Status |
|---|---|
python3 scripts/langs_check.py |
PASS |
python3 scripts/docs_check.py |
PASS |
python3 scripts/memory_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 |
| OpenAPI/language JSON parse | PASS |
Shell bash -n |
PASS in source/release checks |
go test ./... in docker-agent |
PASS |
| Python source parsing/contract checks | PASS |
python3 scripts/check_source.py |
PASS |
python3 scripts/release_smoke.py |
PASS |
./dev.sh test Rust-independent phases |
PASS; Rust phase BLOCKED because Cargo is unavailable |
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 test --locked --all-targets / Rust phase of ./dev.sh test |
BLOCKED: Rust/Cargo toolchain unavailable in this workspace |
| Live H1/H2/H3 Web Server integration and large-file acceptance | release-host acceptance gate |
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.