Hacktoberfest 2026:メンテナが10月に向けて印を付けた、オープンで初心者向けの issue。 Hacktoberfest の issue を見る

HTTP/2 body pipe sends 1-byte DATA frames when a stream holds a sliver of capacity

クローズ
#4,211 コメント 1 件 リアクション 0 件 担当者 0 名 GitHub で見る

メンテナーはふだん 1 日以内に返信

まだ誰も着手していません。

評価

難易度
3/5
見積もり時間
1〜2日
初心者へのやさしさ
74/100
issue の種類
バグ
明瞭さ
明確に書かれている
活発さ
活発
技術スタック
rust

調査の方向性

Start in src/proto/h2/mod.rs at PipeToSendStream, then run the regression test h2_chunk_waits_for_useful_capacity_instead_of_sliver_frames from the linked PR. Trace how capacity is claimed before send_data; done means Stream B no longer emits a 1-byte initial DATA frame when only a sliver of connection capacity is available.

索引モデルが issue の本文から書いたものです。

説明

Version
hyper 1.9.0 through master (c954d80), with h2 0.4.19.

Platform
Any. Seen on Linux and macOS.

Description

When a stream holds only a tiny amount of send capacity, the HTTP/2 client and server body pipe (PipeToSendStream in src/proto/h2/mod.rs) hands a body chunk to h2 anyway, and h2 splits it into DATA frames sized to that capacity. The body then goes out as a 1-byte DATA frame, followed by more small frames as capacity trickles in (silly-window syndrome).

On master, the pipe reserves a 1-byte claim once a chunk is in hand, then calls send_data as soon as capacity() > 0. hyper 1.9.0 reserved the byte before polling the body; the result is the same. On a connection whose window is nearly used up, that one byte is often all the stream has been assigned, so the first frame carries a single byte of a 10 KB chunk.

This used to cost only framing overhead. Since h2 0.4.16, it breaks connections. h2 servers (tonic, axum, hyper) now charge every non-final DATA frame under 256 bytes against a per-connection budget (DEFAULT_DATA_FRAME_OVERHEAD_THRESHOLD, a minimum of 25600). When that budget runs out they send GOAWAY(ENHANCE_YOUR_CALM, "too_many_data_frames"), and every in-flight stream on the connection fails.

We hit this in a reverse proxy that keeps pooled HTTP/2 connections to a hyper backend with adaptive_window(true). Adaptive windows start at 65535, so a busy pooled connection often uses up its connection window. A frame trace showed about 2,900 frames of sz=10240, available=1 in 4 seconds, and the backend GOAWAY'd the pooled connection every few seconds.

Reproduction

The regression test in the linked PR (h2_chunk_waits_for_useful_capacity_instead_of_sliver_frames) reproduces it deterministically:

  1. Stream A sends 65534 bytes, which the server does not release, leaving one byte of connection window.
  2. Stream B then sends a 10 KB body.
  3. On master, stream B's first DATA frame is 1 byte.

Proposed fix

Keep the small claim that #4003 depends on, but make it big enough to cut a useful frame. Reserve min(len, 1024) and wait until that much is assigned before calling send_data. 1 KiB is well below any stream window a real peer advertises, so this cannot hold a chunk back indefinitely, and it rules out sub-256-byte frames.

主要言語
Rust
スター
16.4k
フォーク
1.8k
平均マージ
2日 9時間
マージ済み PR(30日)
14

環境構築

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

hyperium/hyper のほかの issue

hyperium/hyper の issue をすべて見る

似ている issue

Rust の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。