hyperium / hyperium/h3

Request reset cannot be observed independently while body polling is paused

Open
#352 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Rust
Stars
890
Forks
136
Avg merge
14d 20h
Merged PRs (30d)
2

Description

Version

h3 0.0.8, h3-quinn 0.0.10

Platform

Linux desktop 7.1.7 NixOS x86_64 GNU/Linux

Summary

Request reset is invisible while body polling is paused by application backpressure

Code Sample
let (body_tx, mut body_rx) = tokio::sync::mpsc::channel::<Bytes>(1);

// Fill the bounded application queue and stop consuming it.
body_tx.send(Bytes::from_static(b"first")).await?;
let reserve = body_tx.reserve();
tokio::pin!(reserve);

// Client now RESET_STREAMs the request body.
client.reset_request(STREAM_CANCEL_CODE)?;

// The server waits for application capacity and intentionally does not call
// recv.poll_data(). The h3 API has no separate reset event to select here.
assert!(tokio::time::timeout(Duration::from_millis(250), &mut reserve)
    .await
    .is_err());

Once the queue is drained and poll_data() resumes, h3 can return StreamErrorIncoming::StreamTerminated; the delayed visibility is the issue.

Expected Behavior

Request-stream reset should be independently observable even when body delivery is paused, allowing server work and buffered application state for that RPC to be cancelled promptly.

Actual Behavior

A peer RESET_STREAM is surfaced as StreamErrorIncoming::StreamTerminated only when the receive stream is polled. If an application has paused body polling because its bounded downstream channel is full, h3 exposes no independent per-stream reset future to select alongside that application backpressure.

Polling whole-connection closure does not solve this: a stream reset is intentionally local to one stream and does not close the QUIC connection.

Suggested upstream fix

Expose stream reset/closure as an independently pollable event, or define a split receive abstraction where body data and terminal/reset state can be driven without competing for the same mutable polling operation.

Contributor guide

Open the contributing guide

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.

Research direction

Start by running the supplied Tokio reproduction with a bounded channel, paused body polling, and client.reset_request(STREAM_CANCEL_CODE). Trace how recv.poll_data() produces StreamErrorIncoming::StreamTerminated and assess the proposed split or independently pollable reset event; done means a server can observe the per-stream reset while application backpressure still blocks body delivery.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
backend-api-design, networking
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Needs clarification
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.