Hacktoberfest 2026:维护者为十月标记出来的 issue,仍然开放、适合新手。 浏览 Hacktoberfest issue

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

未关闭
#4,211 0 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

维护者通常 2 天内回复

还没有人认领这个 Issue。

评估

难度
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.3k
派生
1.8k
平均合并
4 天 7 小时
30 天内合并 PR
10

环境准备

  • 没有 Dockerfile 或 Docker Compose 文件
  • 没有 Pull Request 模板
  • 阅读贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

hyperium/hyper 的其他 Issue

查看 hyperium/hyper 的全部 Issue

相似的 Issue

更多 Rust Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。