Skip to content

Apply backpressure before reading more frames - #344

Merged
seanmonstar merged 2 commits into
hyperium:masterfrom
Streetblock:feat/issue-308-buffer-bound-reproducer
Aug 7, 2026
Merged

Apply backpressure before reading more frames#344
seanmonstar merged 2 commits into
hyperium:masterfrom
Streetblock:feat/issue-308-buffer-bound-reproducer

Conversation

@Streetblock

@Streetblock Streetblock commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Summary

Decode complete frames already present in FrameStream's receive buffer before polling the underlying QUIC transport for another chunk.

This prevents a slow frame consumer from causing BufRecvStream to accumulate a new transport chunk on every wake while complete frames are still buffered.

Root cause

FrameStream::poll_next called try_recv before attempting to decode the existing buffer. If one transport chunk contained multiple HTTP/3 frames, every subsequent frame poll could read and append another chunk before consuming the frames already available.

Regression test

The new deterministic test models 64 immediately available transport chunks, each containing 16 HEADERS frames with a 1,024-byte payload, while the consumer processes one frame per wake.

On current master, the test observed:

  • 64 underlying transport polls
  • 985,920 bytes left buffered after consuming 64 frames
  • one encoded transport chunk is 16,432 bytes

With this change:

  • only 4 transport polls are needed for the same 64 frames
  • buffering remains bounded to the currently consumed transport chunk

Validation

  • cargo fmt --all -- --check
  • cargo test -p h3 -p h3-quinn
  • 228 unit tests passed
  • 9 documentation tests passed

Prior and related work

After opening this draft, I noticed the issue timeline links to 0x676e67/http3#2. That June 2026 fork patch already contains the equivalent FrameStream reordering and a smaller two-frame regression test, alongside unrelated QPACK changes. Credit to @0x676e67 for that earlier implementation.

This draft was developed independently against current upstream master; its additional contribution is the stronger multi-chunk regression scenario and measured baseline above. Maintainers may prefer to adapt the earlier commit or this focused patch, and I am happy to adjust attribution or approach accordingly.

The same regression scenario also passes on the broader receive-buffer refactor in #328. This draft offers a smaller near-term change while that larger design is evaluated.

Fixes #308

Decode complete buffered frames before polling the QUIC transport again. This bounds FrameStream buffering to the current transport chunk under a slow consumer.
@seanmonstar

Copy link
Copy Markdown
Member

This looks good to me, reason it's still a draft?

@Streetblock
Streetblock marked this pull request as ready for review August 7, 2026 20:28
@Streetblock

Copy link
Copy Markdown
Contributor Author

Oops, my bad! Leaving it as a draft was just an oversight. I just marked it as ready for review. Thanks!

@seanmonstar
seanmonstar merged commit c916ed5 into hyperium:master Aug 7, 2026
16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

poll_read data is buffered without bounds

2 participants