5.2 KiB
RustProxy 0.26.1 implementation note
Scope
Version 0.26.1 is a focused follow-up to the persistent protocol diagnostics and Stored Logs explorer introduced in 0.26.0. It does not change SQLite schema 8 or the saved proxy configuration format.
The release has two goals:
- Attribute persistent
protocol_errorrecords to a configured vhost when that attribution is safe and deterministic. - Make the Stored Logs explorer practical on installations with many vhosts and useful for protocol diagnostics.
Live Logs remains a separate bounded in-memory request view. Low-level protocol_error records are persistence-only and must not be published to its history/broadcast path.
One shared vhost-resolution function
All protocol adapters use the same resolver; TLS, HTTP/1, HTTP/2 and HTTP/3 must not implement independent hostname matching.
resolve_logging_vhost(
local,
tls,
routed_vhost,
authority,
host,
sni,
) -> Option<ResolvedLogVhost>
Resolution priority is:
- a vhost already selected by normal routing;
- HTTP
:authority; - HTTP
Host; - TLS/QUIC SNI;
- no match, which means
_unmatched.jsonlin per-vhost file mode.
The helper normalizes authority/Host/SNI with the existing host parser and delegates selection to the same Snapshot::frontend exact/wildcard and listener-binding logic used by normal request routing. It returns the configured internal vhost ID and matched_by; client input is never turned directly into a filename.
Persistent protocol records
A protocol record keeps the compatibility fields from 0.26.0 and also exposes canonical diagnostics when available:
event = protocol_error;reasonand compatibilityprotocol_error;errorand compatibilityerror_detail;client_ipandlocal_addr;transportandhttp_version;vhostwhen safely resolved;sniand compatibilitytls_sni;authority;matched_by = router | authority | host | sni | none.
Diagnostic identity strings are control-character stripped and length-bounded before persistence. Existing secret redaction and error-detail limits remain in force.
In per-vhost file mode, a resolved record uses the existing configured vhost sink. Invalid internal vhost identifiers fall back to _unmatched instead of being sanitized into a new filename. In combined-file mode, sink behavior is unchanged.
Protocol integration
TLS reads SNI from ClientHello before completing the handshake. A later handshake failure/timeout carries that SNI into the shared resolver. If ClientHello itself cannot be parsed, attribution remains unavailable and the record is unmatched.
HTTP/2 retains the TLS SNI for post-handshake connection/drain diagnostics. Request paths that have an HTTP request object can additionally provide authority/Host.
HTTP/3 obtains SNI from Quinn/Rustls handshake data after a successful QUIC handshake and uses it for later request, stream and connection protocol failures. Failures that happen before usable handshake identity exists remain unmatched.
No protocol path infers a vhost solely from a shared listener or local port.
Stored Logs explorer changes
The /logs workspace now:
- highlights the selected log row;
- expands Record details inline directly below that row;
- removes the separate details panel below the table;
- keeps the table header sticky while the log list scrolls;
- lets each administrator choose visible Stored Logs columns and persists the choice in existing account preferences;
- offers protocol columns for transport, match source, SNI and authority;
- keeps the configured-file inventory collapsed by default;
- canonicalizes fields through the active structured-log field mapping so
client_ipremains visible when the JSON output key was renamed; - searches record values case-insensitively and includes
reason,error,sni,authorityand other stored values; - refreshes keyword results with a short debounce while typing;
- retains the existing bounded source/byte/line/page limits and reports truncation when an
allquery contains more sources than can be scanned safely.
Security invariants
The browser still accepts only opaque configured source IDs; it never accepts arbitrary filesystem paths. File reads remain regular-file-only and retain Unix O_NOFOLLOW protection.
SNI, Host and authority are lookup inputs only. They cannot select a filesystem path directly. Only a configured vhost resolved through the existing routing model can select a per-vhost log sink.
Regression coverage
Source tests cover:
- exact and wildcard hostname precedence using the shared resolver;
- router priority over authority/Host/SNI;
- Host with port and case-insensitive normalization;
- unknown and missing SNI returning no vhost;
- mapped
client_ipnormalization in Stored Logs; - keyword matching against protocol diagnostic values;
- safe per-vhost filename fallback;
- bounded protocol identity fields;
- protocol errors remaining outside Live Logs;
- preference validation for selectable Stored Logs columns.
A Rust-enabled release host must still run cargo fmt --check, Clippy with warnings denied, all-target/all-feature tests and the complete dev.sh release build before the package is considered compiler-verified.