Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

Upgraded HTTP/2 CONNECT streams cannot be reset, so a failed tunnel looks like a clean close

Open
#4,209 0 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 2 days

Nobody has claimed this yet.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
55/100
Issue type
Feature
Clarity
Mostly clear
Activity status
Active
Tech stack
rust

Research direction

Start with proto::h2::upgrade::pair, H2Upgraded::poll_shutdown, and UpgradedSendStreamTask::tick to trace how shutdown becomes END_STREAM. Then inspect how Upgraded::downcast reaches upgrade implementations. Done means an HTTP/2 CONNECT upgrade can queue CONNECT_ERROR while HTTP/1 upgrades remain unchanged, including the reported tunnel-reset scenario.

Written by the indexing model from the issue text.

Description

Is your feature request related to a problem? Please describe.

A server that accepts an HTTP/2 CONNECT (or extended CONNECT) gets the
tunnel from hyper::upgrade::on as an Upgraded. hyper offers no way to end
that stream with an error. Dropping the Upgraded, or shutting it down, always
sends a clean END_STREAM. A proxy whose tunnelled connection fails therefore
cannot tell the client, and the client cannot tell a failed tunnel from a
complete one.

RFC 9113, section 8.5:

A proxy treats any error in the TCP connection, which includes receiving a
TCP segment with the RST bit set, as a stream error (Section 5.4.2) of type
CONNECT_ERROR.

The same applies to a client-side Upgraded whose local end fails.

Versions: hyper 1.9.0. master (1.11.1) has the same code.

Mechanism
  • proto::h2::upgrade::pair splits the stream. H2Upgraded keeps the
    RecvStream and an mpsc sender. The SendStream moves into
    UpgradedSendStreamTask, which the executor runs.
  • H2Upgraded::poll_shutdown closes the channel. Dropping H2Upgraded drops
    the sender, which also closes it.
  • UpgradedSendStreamTask::tick answers a closed channel with
    send_data(SendBuf::None, true), which is END_STREAM.
  • H2Upgraded is pub(super) in the private proto module, so
    Upgraded::downcast cannot reach it, and the SendStream is owned by the
    task anyway.

So there is no path from user code to SendStream::send_reset.

Reproduction
  1. Serve HTTP/2 with hyper and accept a CONNECT; respond 200 and await
    hyper::upgrade::on(req).
  2. Relay the Upgraded to a TCP connection, and have the remote end of that
    TCP connection reset (for example SO_LINGER=0 then close).
  3. The relay sees ECONNRESET and drops the Upgraded.
  4. The h2 client's response body ends with None (END_STREAM), exactly as it
    would after a normal FIN. It never sees an error.

Describe the solution you'd like

A small method on Upgraded that queues RST_STREAM(CONNECT_ERROR) for an
HTTP/2 upgrade and returns whether it did, for example
Upgraded::reset_with_connect_error(&mut self) -> bool. It is a no-op that
returns false for an HTTP/1 upgrade. Internally a oneshot carries the reason
to UpgradedSendStreamTask, which checks it before reading the data channel,
so a reset queued just before a drop still wins over the END_STREAM.

Describe alternatives you've considered

A version that takes any error code (h2::Reason is not public in hyper, so a
u32 or a new hyper type) would also work; CONNECT_ERROR is the code the RFC
names for this case. We carry the patch in a vendored copy and can send a PR.

Additional context

We hit this in an HTTP/2 CONNECT tunnel relay (HBONE) and currently carry the change as a patch on a vendored hyper 1.9.0. Happy to open a PR against master.

Dominant language
Rust
Stars
16.3k
Forks
1.8k
Avg merge
2d 13h
Merged PRs (30d)
10

Getting set up

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from hyperium/hyper

All issues in hyperium/hyper

Similar issues

More Rust issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.