test(http2): cover small flow-control windows - #4212
jeremyjpj0916 wants to merge 3 commits into
Conversation
A body chunk was handed to h2 once the stream held any capacity. h2 cuts DATA frames from the capacity a stream holds, so on a connection whose window was nearly spent a chunk left as a 1-byte frame followed by more slivers. h2 0.4.16+ servers charge small non-final DATA frames to a per-connection budget and GOAWAY the connection with ENHANCE_YOUR_CALM when it runs out. Reserve min(len, 1024) instead of 1 and wait until that much is assigned. The claim stays small, so hyperium#4003 still holds, but no sub-1 KiB first frame is cut from a larger chunk. Closes hyperium#4211
|
I think this causes other problems, making streams hang if the peer sets a smaller window than what is defined here as "useful". |
Remove the fixed 1 KiB body-capacity gate because peers may legally advertise a smaller stream window. Add regressions showing that a 512-byte peer window and the final byte of connection capacity both make request-body progress.
|
Sean, your concern was correct. I reproduced the hang through Ferrum Edge 0.9.10 against a legal 512-byte peer stream window: the backend received the request headers but zero body bytes before timeout. I removed the fixed 1 KiB gate and replaced the original test with regressions requiring progress through a 512-byte stream window and with only one connection-window byte available. I also opened hyperium/h2#965 to make h2's automatic DATA-frame budget follow runtime target-window changes, as suggested in #4211. |
|
Closing this PR as superseded by hyperium/h2#965. The review feedback was correct on both points: a fixed minimum send threshold can deadlock a peer's smaller legal stream window, and the receiver-side DATA-frame budget should follow runtime target-window changes. Ferrum Edge 0.9.10 reproduced the former with a 512-byte backend stream window: headers arrived, but zero body bytes did. The corrected Ferrum build sends the full 2,048-byte wire body, beginning with a 512-byte DATA frame. Hyper therefore needs to keep making progress whenever capacity is positive; h2#965 contains the actual budget fix. The test-only commits here and Ferrum's permanent regressions preserve the evidence, but this PR no longer fixes #4211 by itself. |
The original version of this PR waited for at least 1 KiB of HTTP/2 send capacity before handing a body chunk to h2. Review correctly identified that this can hang when a peer advertises a smaller stream window.
I reproduced that failure through Ferrum Edge 0.9.10 with a standards-compliant h2 backend using a 512-byte stream window: request headers reached the backend, but the backend received zero body bytes until the request timed out. A fixed positive threshold cannot distinguish a transient connection-window sliver from all of the capacity a peer has made available, so Hyper must allow body progress whenever capacity is nonzero.
This revision removes the 1 KiB gate and adds two deterministic regression tests:
WINDOW_UPDATE.The receiver-side protection against excessive small DATA frames belongs in h2. hyperium/h2#965 updates h2's automatic DATA-frame budget whenever adaptive flow control changes the target connection window, preserving explicit budgets and outstanding charges.
Validation:
cargo test --features full --test client(70 passed)cargo fmt --all -- --checkRelated: #4211