v0.31.5
This commit is contained in:
1 parent
75104f87ba
commit
4cc994b3bc
86 files changed
+942
-223
No files matched your search
@@ -45,6 +45,17 @@ At least one column must remain visible. Stored-log column selection is saved pe
|
||||
|
||||
Selecting a row highlights it and expands parsed field/value pairs directly below the row. A nested **Raw JSON** section shows the normalized complete record.
|
||||
|
||||
## Narrow-screen navigation (0.31.5)
|
||||
|
||||
At viewport widths up to 700px, `/logs` uses a vertically scrolling list of
|
||||
compact cards in place of a horizontally expanding results table. Each card
|
||||
shows every enabled column, with long values wrapped or shortened until
|
||||
expanded; tap the card (or focus and press Enter/Space) to inspect all parsed
|
||||
fields and the complete Raw JSON. Search, source, page size, column selection,
|
||||
pagination and repeated-value analysis stay available. Large raw text and
|
||||
aggregate tables scroll **inside their own containers**, never across the entire
|
||||
administration page. Tablet/desktop results keep the normal tabular layout.
|
||||
|
||||
## Repeated-value analysis
|
||||
|
||||
The **Repeated values** tab (advanced parser) can count repeated values for any parsed field returned by the explorer. Typical security-investigation fields are `user_agent`, `client_ip`, `host` and `path`. Counts are calculated across the bounded matching scan before pagination, so changing the page does not change the count set. Minimum repetitions and top-result count are configurable within server limits. Values in the result table are directly copyable.
|
||||
|
||||
+29
-1
@@ -7,7 +7,7 @@ conformance, interoperability or production performance until the acceptance tes
|
||||
## Stack and configuration
|
||||
|
||||
The adapter delegates QUIC transport/TLS to Quinn 0.11.12 and HTTP/3/QPACK plus the
|
||||
Quinn adapter to `hpx-h3 2.5.19` with its `quinn` feature. The crate is imported as `h3`
|
||||
Quinn adapter to `hpx-h3 2.5.20` with its `quinn` feature. The crate is imported as `h3`
|
||||
in source. These are Cargo dependencies, not bundled binaries.
|
||||
Rustls provides TLS 1.3 for QUIC; SNI certificates come from the existing inventory.
|
||||
HTTP/1.1 and optional HTTP/2 remain on TCP at the same port. HTTP/3 is on UDP.
|
||||
@@ -113,6 +113,34 @@ is no separate external-port override. Open UDP as well as TCP in your firewall/
|
||||
balancer. Scope labels do not perform those operations. Clients lacking QUIC or blocked
|
||||
UDP can still connect using TCP; no guarantee is made about browser protocol preference.
|
||||
|
||||
## H3 full-page navigation to HTTP/1.1 backend (0.31.6)
|
||||
|
||||
The RustProxy logo remains a normal `href="/"` link, not a client-side panel change. On an H3-enabled frontend it produces a new document GET through the proxy. When forwarding an H3 GET/HEAD to an HTTP/1.1 backend, RustProxy now probes for the stream's end for at most 35 ms per initial frame. A finished empty request is passed to H1 with a confirmed complete receive half rather than an unknown body state. Hyper already special-cases H1 GET/HEAD framing; no claim is made that ordinary GET requests were chunked. A nonempty frame and all subsequent bytes are replayed without buffering the whole request. The slow-peer case falls back to regular streaming.
|
||||
|
||||
If `h3.accept()` fails, existing request tasks get the normal bounded drain instead of immediate mass abort. The new diagnostics use status=0 for cancellations (not a real HTTP response), and persist interrupted-response details including `phase=`, `stream_id=`, `method=`, `path=`, `response_status=`, `body_bytes_sent=` and `error=` in the bounded, redacted `error_detail`. These are stored per vhost when file logging is enabled; the normal access logs remain available for successful document and asset GETs.
|
||||
|
||||
**iOS validation procedure:** keep H3 on, click the logo repeatedly on an authenticated panel behind the real RustProxy vhost, and collect timestamps for `http3_peer_cancelled_before_headers`, `http3_peer_cancelled_after_headers`, `http3_response_write_error`, `http3_accept_error`, and the GET `/` and asset access records. Collect browser Web Inspector Network/QUIC trace if a blank document persists. Correlate the **new GET/** status and transmitted bytes with older cancelled streams. Mere cancellation of an obsolete API or SSE stream is not proof that the new document failed. This implementation is not proven to resolve an iOS issue until live tests pass.
|
||||
|
||||
## Browser refresh and stream cancellation (0.31.5)
|
||||
|
||||
A browser may cancel an obsolete H3 stream when the user reloads or leaves a
|
||||
page, sometimes before its HEADERS arrive. RFC 9114 `H3_REQUEST_CANCELLED`
|
||||
(and a peer-originated `H3_NO_ERROR` reset) is not itself a server-side HTTP 400.
|
||||
RustProxy therefore omits that fabricated 400 access-log entry and avoids
|
||||
adding `H3_INTERNAL_ERROR` to a directly identified cancelled response stream.
|
||||
Malformed or forbidden headers still yield a protocol-error 400.
|
||||
|
||||
This correction does **not** establish the cause of a blank document after F5.
|
||||
If the new navigation fails, compare its actual document/asset statuses over H3
|
||||
and H2, the configured reverse-proxy Host/Origin/forwarded-proto chain, and any
|
||||
connection-level QUIC errors. An error record without HTTP method, path and
|
||||
request headers cannot identify the browser document which failed. Capture
|
||||
browser network traces and QUIC qlogs with timestamps for live acceptance.
|
||||
|
||||
Per-vhost `http2_enabled`/`http3_enabled` toggles also no longer rotate the global
|
||||
HOT/COLD cache identity. Origin representation policy and cache invalidation are
|
||||
unchanged; the frontend protocol remains part of live request routing.
|
||||
|
||||
## Verification gate
|
||||
|
||||
```bash
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
# RustProxy 0.31.6 implementation and acceptance gate
|
||||
|
||||
## Scope
|
||||
|
||||
This patch is based on the delivered 0.31.5 source archive. It is a narrow HTTP/3 navigation follow-up. It does not change the logo link, normal panel SPA navigation, administrator security checks or the HTTP/3 listener controls. The report of iOS `21.0.1` is operator-provided device metadata and has not been independently verified.
|
||||
|
||||
## Code changes
|
||||
|
||||
1. `src/proxy/cache_helpers.rs`: the cache/404 empty-body preflight is now bounded to 35 ms per initial frame for H3 GET/HEAD. A delayed FIN bypasses cache rather than blocking the entire route; all frames remain available for streaming. Separately, the H3-to-H1 unknown-length request-body normalization now includes `GET` and `HEAD`. The first meaningful frame is inspected up to eight times, and GET/HEAD wait for at most 35 ms per frame. If end-of-stream is observed, the body becomes an exact, empty H1 request. Nonempty DATA and trailers are replayed via the existing `ReplayBody` wrapper. A slow stream is not discarded or buffered and stays on the existing streaming path. This makes the H3 receive half complete before H1 forwarding when FIN is already available, without relying on a claim that H1 GET/HEAD were chunked (Hyper already special-cases those methods).
|
||||
2. `src/http3.rs`: a failure of the H3 accept loop logs the event and stops accepting, but lets the existing bounded drain handle responses already in progress instead of aborting all response tasks immediately.
|
||||
3. `src/http3.rs`: pre-HEADERS peer stream cancellations are logged at HTTP status **0**, never fabricated HTTP 400. Response failures record the transport stage, H3 stream identifier, method, path without query, advertised response status, bytes successfully sent and bounded/redacted error in per-vhost protocol-error logs. Peer-initiated cancellation remains distinct from a true truncated/error response.
|
||||
4. A full HTTP/3 `GET /` emits `http3_navigation_started` and `http3_navigation_complete` at INFO in the process/service logs (or `http3_navigation_interrupted` at WARN) with SNI, connection endpoints, stream ID, response status and sent bytes. No query, Cookie, Authorization or body content is included. Per-vhost HTTP/3 protocol errors are logged separately in JSONL when enabled. Correlate a missing completion for the new stream rather than assuming any cancellation caused a blank screen.
|
||||
5. No change to the logo anchor `href="/"`, browser code paths, SSE on-page behavior, SQL schema, settings JSON, H1 WebSockets, QUIC RFC 9220 support, HOT/COLD cache or the `/logs` responsive view.
|
||||
|
||||
## Tests and risk
|
||||
|
||||
Rust unit tests cover empty and nonempty GET and HEAD forwarding, cache/404 preflight and stalled-client bounds; these are **source-level additions**, not proof of execution unless Cargo is available. The repository ships static checks, Node UI tests, SQLite upgrade smoke and Go tests. The pinned Cargo.lock dependency graph has not been re-resolved in this environment; a compiler-enabled build host must run `scripts/resolve_dependencies_0312.sh`, `./dev.sh check`, `./dev.sh test`, and a release build before deploying.
|
||||
|
||||
Reproduce on the actual iPhone with H3 **enabled**: open `https://rp.h.linuxiarz.pl`, sign in, click the original RustProxy logo repeatedly, compare successful GET `/` and JS/CSS access events with `http3_*` diagnostic events from the same peer and timestamp. In a failure capture Safari Web Inspector Network entries for document, JS and CSS, a QUIC packet/qlog trace if available, and the vhost JSONL. With systemd installations, view navigation breadcrumbs with `journalctl -u rustproxy --since '10 minutes ago' | grep 'http3_navigation_'`; the service log is separate from vhost JSONL. Old `H3_REQUEST_CANCELLED` events may be harmless; a failed new navigation or incomplete response is the acceptance condition. Test H1/H2, unrelated vhosts, cache retention and `/logs` mobile width as regressions.
|
||||
|
||||
**Acceptance remains OPEN** until compiled and tested on a real HTTP/3 listener with mobile devices; the original white-screen cause is not proven from one cancellation log alone.
|
||||
+2
-1
@@ -31,6 +31,7 @@ This is the canonical index for the current project documentation. The authentic
|
||||
- [0.26.3 implementation note](V0.26.3_IMPLEMENTATION.md) - global interface scaling, chart themes, square draft dock and Settings navigation polish.
|
||||
- [0.26.2 implementation note](V0.26.2_IMPLEMENTATION.md) - unified Logs navigation, field-query search, dynamic JSON columns and RAW parsing.
|
||||
- [0.26.1 implementation note](V0.26.1_IMPLEMENTATION.md) - historical vhost-aware protocol logging and Stored Logs UX milestone.
|
||||
- [0.31.6 H3 iOS navigation hardening and diagnostic events](IMPLEMENTATION_0.31.6.md) - bounded empty GET/HEAD handling, H3 error draining and mobile reproduction.
|
||||
- [0.31.5 User-Agent blocking and consolidated log analysis](IMPLEMENTATION_0.31.5.md) - global/per-vhost UA blocklists, Traffic copy actions, repeated-value aggregation and per-vhost gzip consolidation.
|
||||
- [0.31.4 administration public Origin and settings](IMPLEMENTATION_0.31.4.md) - opt-in HTTPS origin, one-field DNS allowlist, additional hosts in advanced settings, legacy deduplication, CSRF and remaining deployment checks.
|
||||
- [0.31.3 mobile session / invalid-Origin recovery](IMPLEMENTATION_0.31.3.md) - deterministic BFCache and visibility session coordination, 403 diagnostics, recovery and remaining acceptance.
|
||||
@@ -84,7 +85,7 @@ This is the canonical index for the current project documentation. The authentic
|
||||
|
||||
## Historical or version-labelled context
|
||||
|
||||
Version-labelled `V*.md` files are retained as historical implementation/audit records. Their version number describes the audited milestone. The current release implementation note is [IMPLEMENTATION_0.31.5.md](IMPLEMENTATION_0.31.5.md); [IMPLEMENTATION_0.31.4.md](IMPLEMENTATION_0.31.4.md) is retained as the previous administration-Origin milestone; [IMPLEMENTATION_0.31.3.md](IMPLEMENTATION_0.31.3.md) is retained as the previous mobile recovery milestone; [IMPLEMENTATION_0.31.1.md](IMPLEMENTATION_0.31.1.md) is retained as the prior mobile milestone; [IMPLEMENTATION_0.31.0.md](IMPLEMENTATION_0.31.0.md) is retained as the previous milestone; [V0.29.1_IMPLEMENTATION.md](V0.29.1_IMPLEMENTATION.md) is retained as historical context, and [V0.29.0_IMPLEMENTATION.md](V0.29.0_IMPLEMENTATION.md) is retained as the prior redirect/health/cache/log milestone; [V0.28.2_IMPLEMENTATION.md](V0.28.2_IMPLEMENTATION.md) is retained as the prior certificate-hardening milestone; [V0.28.1_IMPLEMENTATION.md](V0.28.1_IMPLEMENTATION.md) is retained as the prior external-path milestone; [V0.28.0_IMPLEMENTATION.md](V0.28.0_IMPLEMENTATION.md) is retained as the prior GeoIP/listener/cache milestone, and [V0.27.3_IMPLEMENTATION.md](V0.27.3_IMPLEMENTATION.md) is retained as the prior HTTP/3/cache-maintenance milestone, [V0.27.2_IMPLEMENTATION.md](V0.27.2_IMPLEMENTATION.md) is retained as the prior managed-ACME repair, [V0.27.1_IMPLEMENTATION.md](V0.27.1_IMPLEMENTATION.md) as the prior managed-runtime/list-sorting milestone, and older version notes remain historical evidence. The latest retained audit is [V0.25.5_AUDIT.md](V0.25.5_AUDIT.md); older audit files remain available for traceability.
|
||||
Version-labelled `V*.md` files are retained as historical implementation/audit records. Their version number describes the audited milestone. The current release implementation note is [IMPLEMENTATION_0.31.6.md](IMPLEMENTATION_0.31.6.md); [IMPLEMENTATION_0.31.5.md](IMPLEMENTATION_0.31.5.md) is retained as the previous log/cache milestone; [IMPLEMENTATION_0.31.4.md](IMPLEMENTATION_0.31.4.md) is retained as the previous administration-Origin milestone; [IMPLEMENTATION_0.31.3.md](IMPLEMENTATION_0.31.3.md) is retained as the previous mobile recovery milestone; [IMPLEMENTATION_0.31.1.md](IMPLEMENTATION_0.31.1.md) is retained as the prior mobile milestone; [IMPLEMENTATION_0.31.0.md](IMPLEMENTATION_0.31.0.md) is retained as the previous milestone; [V0.29.1_IMPLEMENTATION.md](V0.29.1_IMPLEMENTATION.md) is retained as historical context, and [V0.29.0_IMPLEMENTATION.md](V0.29.0_IMPLEMENTATION.md) is retained as the prior redirect/health/cache/log milestone; [V0.28.2_IMPLEMENTATION.md](V0.28.2_IMPLEMENTATION.md) is retained as the prior certificate-hardening milestone; [V0.28.1_IMPLEMENTATION.md](V0.28.1_IMPLEMENTATION.md) is retained as the prior external-path milestone; [V0.28.0_IMPLEMENTATION.md](V0.28.0_IMPLEMENTATION.md) is retained as the prior GeoIP/listener/cache milestone, and [V0.27.3_IMPLEMENTATION.md](V0.27.3_IMPLEMENTATION.md) is retained as the prior HTTP/3/cache-maintenance milestone, [V0.27.2_IMPLEMENTATION.md](V0.27.2_IMPLEMENTATION.md) is retained as the prior managed-ACME repair, [V0.27.1_IMPLEMENTATION.md](V0.27.1_IMPLEMENTATION.md) as the prior managed-runtime/list-sorting milestone, and older version notes remain historical evidence. The latest retained audit is [V0.25.5_AUDIT.md](V0.25.5_AUDIT.md); older audit files remain available for traceability.
|
||||
|
||||
Older context documents such as [INTEGRATIONS_040](INTEGRATIONS_040.md), [MANAGEMENT](MANAGEMENT.md), [SECURITY_AUDIT](SECURITY_AUDIT.md), [ACME_RFC2136](ACME_RFC2136.md) and older version audits remain available for traceability but should not override the current functional/technical documents above.
|
||||
|
||||
|
||||
+21
-1
@@ -1,4 +1,24 @@
|
||||
# Verification report - RustProxy 0.31.5
|
||||
# Verification report - RustProxy 0.31.6
|
||||
|
||||
## 0.31.6 - iPhone H3 full navigation and observability (2026-10-11)
|
||||
|
||||
- **Target:** iPhone Safari and Chrome when an existing dashboard session navigates through the unchanged sidebar logo link (`<a class="brand" href="/">`). It creates an H3 document GET while older SSE/API requests can be cancelled.
|
||||
- **Fix candidates implemented:** The H3 GET/HEAD cache and 404 preflight avoids unbounded waiting on a delayed request FIN; on an H3->HTTP/1.1 vhost, a truly empty GET or HEAD stream is normalized before forwarding (bounded 35 ms first-frame probe; nonempty data replayed; pending client keeps streaming). On an H3 accept error, no longer `abort_all` active responses; bounded drain still applies.
|
||||
- **Diagnostics:** Persist `http3_peer_cancelled_before_headers` events with status 0 (not 400). For interrupted responses write `http3_peer_cancelled_after_headers` or `http3_response_write_error`, including sanitized path without query, stream ID, response phase/status, bytes sent and redacted error. Normal process INFO/WARN logs also record the start, completion or interruption of root-document H3 GET `/` using its stream ID; no cookies or query strings. These records remain in vhost file logs and are subject to configured log sinks. They are distinct from application response access logs.
|
||||
- **Rust regression cases added:** GET/HEAD empty-body normalization, nonempty GET payload replay, bounded cache preflight and stalled GET; retained 0.31.5 H3 cancellation classification tests. Static release and documentation contract check extended.
|
||||
- **NOT VERIFIED:** Rust compilation, a live QUIC listener, reverse-proxy-to-panel traffic, iOS Safari/Chrome, frame captures, HTTP/3 stream integrity, TLS/QUIC delivery, persisted data upgrades. Do not describe root cause or fix as proven until captured on device. No WS-over-H3 is assumed; H1 websocket origins do not activate RFC 9220 by themselves.
|
||||
- **No changes:** Sidebar logo link, H3 on/off configuration, SQLite schema 9, cache format, frontend routes, authentication/session/CSRF or WebSocket settings.
|
||||
- **PASS — executed for 0.31.6:** `./dev.sh test` completed all pre-Cargo Python/SQLite/schema/upgrade/security/source checks, 300,000 simulated memory-model operations, 2,000 requests to a Python test peer, all Node UI regressions (including the 0.31.5 mobile/H3 suite updated for the new error path), documents and both language packs. `tools/checks/h3_navigation_0316.py` also passed. The script then exited **127** solely because Rust/Cargo is unavailable. `GOPROXY=off go test ./...` in `docker-agent`, `bash -n dev.sh` and OpenAPI JSON parsing passed. Source guards are not execution of Rust tests.
|
||||
|
||||
## 0.31.5 follow-up - mobile Stored Logs, H3 peer aborts, cache preservation (2026-10-11)
|
||||
|
||||
- **Problem 1, mobile `/logs`:** narrow pages grew horizontally under dynamically selected log columns and large JSON/error fields. CSS now scopes width to the Logs workspace, presents entries as two-column, keyboard-expandable cards at widths `<=700px`, preserves every user-selected field in its card, stacks dense filters, wraps long values, and retains independently horizontally scrollable code/aggregate data. Details and Raw JSON remain accessible. Existing row interaction and per-user column choices are unchanged.
|
||||
- **Problem 2, H3 synthetic status:** `resolver.resolve_request()` returned `StreamError::RemoteTerminate(H3_REQUEST_CANCELLED)` for a browser-cancelled stream before request headers; RustProxy previously called `log_protocol_error(..., 400, ...)`, making a *transport cancellation* appear to be an application HTTP 400 with no method/path. Now peer cancellations (`H3_REQUEST_CANCELLED` or peer `H3_NO_ERROR`) are low-level debug observations, while malformed messages still retain an attributed HTTP 400. Response send errors directly classified as peer cancellations no longer provoke a redundant `H3_INTERNAL_ERROR` reset. We deliberately retain the old `ReceiveBody::Drop` safeguards against h3/quinn pending-read panic.
|
||||
- **Important limit:** the supplied log cannot establish why the new navigation rendered a blank page; an old request may simply have been cancelled by F5. Missing HTTP method, path, authority, User-Agent, and 0 sent bytes prevent correlation to the failed top-level document. The *root cause of the blank page has not been reproduced or verified*. Validate Safari and Chrome with actual RustProxy QUIC/HTTPS, the reverse-proxy Host/Origin/`X-Forwarded-Proto` chain, browser Network waterfall (especially HTML and fingerprinted JS/CSS), and connection-level debug/qlog before accepting the fix as complete.
|
||||
- **Problem 3, cache:** `cache_revision()` used to hash complete vhost configuration, including `http2_enabled` and `http3_enabled`; an unrelated frontend protocol toggle rotated the global compatibility identity and triggered `CacheInvalidation::All`, flushing HOT and COLD. Normalize these two flags to the default `true` only for the cache-identity digest; live routing and serialized configuration remain unmodified. Rust tests cover H2, H3, combined toggles and a true cache-policy edit.
|
||||
- **Problem 4, public origin vs allowlist:** public HTTPS origin fixes scheme + host + port for security checks behind a *trusted* proxy (and implicitly allows its DNS host); extra allowed DNS hosts only expand allowed names. Retain both; improve Polish and English help text, no API/SQLite format changes.
|
||||
- **Verification, 2026-10-11:** `./dev.sh test` passed its entire available Python/SQL/schema/upgrade/security/security-dependency/Node/docs/language pre-Cargo suite, including new `h3_cache_mobile_0315_test.mjs`, then exited **127** because `cargo` is absent. `./dev.sh check` similarly exited **127** for missing Cargo. `GOPROXY=off go test ./...` in `docker-agent` passed. `bash -n dev.sh`, Node syntax, JSON syntax and focused source gates also passed. Rust unit tests were **not compiled or executed**.
|
||||
- **Browser layout smoke:** headless Chromium/Python Playwright rendered a synthetic fixture with the actual HTML/CSS log workspace at widths **320, 375, 430, 700, 768, 1024px**. In every case `body.scrollWidth === innerWidth`; cards were grid rows at `<=700px`, with desktop table rows at 768px+. Parsed fields, long unbroken values and raw JSON were included. This was a *static layout simulation*, **not** authenticated panel/live H3 acceptance.
|
||||
|
||||
## 0.31.5 follow-up - Stored Logs navigation polish
|
||||
|
||||
|
||||
Reference in new issue
Block a user