Files
RustProxy/docs/V0.26.1_IMPLEMENTATION.md
T
2026-10-05 19:05:55 +02:00

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:

  1. Attribute persistent protocol_error records to a configured vhost when that attribution is safe and deterministic.
  2. 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:

  1. a vhost already selected by normal routing;
  2. HTTP :authority;
  3. HTTP Host;
  4. TLS/QUIC SNI;
  5. no match, which means _unmatched.jsonl in 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;
  • reason and compatibility protocol_error;
  • error and compatibility error_detail;
  • client_ip and local_addr;
  • transport and http_version;
  • vhost when safely resolved;
  • sni and compatibility tls_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_ip remains visible when the JSON output key was renamed;
  • searches record values case-insensitively and includes reason, error, sni, authority and 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 all query 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_ip normalization 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.