fix(outbound): surface gRPC and VMess rejections as stream errors - #277
Merged
Merged
Conversation
|
✅ CI report 449a5e0 vs
Tests 22 added, 9 removed, 7 ignored
Measurements 8 metrics, 0 over limit
|
A peer that refuses a gRPC stream used to read as a successful dial followed by a clean EOF: the frame parser treated END_STREAM as the only signal and never looked at HEADERS, RST_STREAM or GOAWAY. The stream now records a failure and reports it from every poll instead of EOF when the peer answers a non-200 `:status`, ends the stream before any DATA (the trailers-only shape a gRPC server declines with), ends it with a non-zero `grpc-status`, resets the stream, or sends a GOAWAY that excludes the stream or carries an error; a graceful GOAWAY past our stream lets it finish. END_STREAM on a HEADERS frame takes effect once its block is complete and judged, so a verdict split over CONTINUATION is not lost. Header blocks are read with a small HPACK reader that keeps the dynamic table and decodes Huffman strings (RFC 7541 appendix B), since h2 encoders Huffman-code `grpc-status`; only `:status` and `grpc-status` are kept. The VMess relay task's result was dropped with its abort handle, so a rejected response header or an invalid chunk closed the duplex and the owner read EOF. The task now records how it ended before its duplex half closes, and the stream reports that error on the poll that would have been EOF (and on writes that fail for the same reason). Closes daeuniverse#274.
Zakkaus
force-pushed
the
fix/outbound-stream-errors
branch
from
September 19, 2026 13:48
2ba3a0c to
47dc9ee
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Peer rejections in gRPC and VMess could surface as clean EOF instead of stream errors, hiding failed proxy exchanges. Closes #274.
How I fixed it
Move gRPC into
transport/grpc.rsusing the existingh2client, with 64 KiB response headers, its default 4 KiB dynamic table, and a 16 KiB owned write batch. Preserve buffered payload, terminal errors, half-close, split-task wakeups, graceful GOAWAY and IPv6 authorities; retain the VMess relay result before duplex closure. Update regression tests and bilingual docs. Upstream h2#959 is merged but not included in the locked 0.4.19. The follow-up gRPC implementation, tests and documentation were LLM-authored and reviewed with Oh My Pi under the maintainer's CONTRIBUTING.md §11 authorization; human approval remains required.Verified
After merging
mainat318edf58,ci/outbound-ci.shandcargo check -p honk-core --all-targetspassed locally. The outbound gate covers formatting, all-target Clippy and tests withrprxoff/on, honk-config, and the 23 transport regressions; the header suite failed 9 cases on original head47dc9eebefore the repair. The two documentation conflicts were checked against both parents, preserving the carrier-pressure and gRPC sections. Full-workspace runtime tests, real-eBPF and external-peer gates were not run locally.