Skip to content

fix: requeue released credit on recv window shrink - #1002

Open
hsdfat wants to merge 1 commit into
hyperium:masterfrom
hsdfat:fix/recv-window-update-after-settings-shrink-976
Open

hsdfat wants to merge 1 commit into
hyperium:masterfrom
hsdfat:fix/recv-window-update-after-settings-shrink-976

Conversation

@hsdfat

@hsdfat hsdfat commented Nov 7, 2026

Copy link
Copy Markdown

Fixes #976

When the local SETTINGS_INITIAL_WINDOW_SIZE is lowered, each stream's receive window is shrunk once the peer ACKs the SETTINGS. That can make capacity the application has already released, but which was being held back to batch WINDOW_UPDATEs, due to be sent. apply_local_settings never queued the stream, so if the peer had no more DATA to send (its window was now non-positive), nothing triggered the update and the stream stalled.

Changes:

  • Recv::apply_local_settings now takes the connection task waker.
  • After dec_recv_window, if unclaimed_capacity() is Some, the stream is pushed onto pending_window_updates and the task is woken, the same way release_capacity does it.
  • Streams::apply_local_settings passes &mut me.actions.task through.

Test: client_decrease_initial_window_size_sends_released_capacity in tests/h2-tests/tests/flow_control.rs. The client receives and releases 16384 bytes (below the update threshold), then lowers the initial window to 1024. After the SETTINGS ACK it expects WINDOW_UPDATE(1, 16384). The test times out waiting for that frame without the fix and passes with it.

The new test passed 60 single runs and 10 full flow_control runs in a row locally. The window update is queued while the SETTINGS ACK is handled in poll2 and flushed by poll_complete in the same Connection::poll, so the ordering does not depend on timing.

Problem:
Lowering SETTINGS_INITIAL_WINDOW_SIZE shrinks each stream's recv window
when the peer ACKs our SETTINGS. That can make capacity the application
already released (held back for batching) eligible for a WINDOW_UPDATE,
but apply_local_settings never queued the stream. The peer could be left
with a non-positive window and no further DATA to trigger an update, so
the stream stalled.

Solution:
After dec_recv_window, queue the stream in pending_window_updates when
unclaimed_capacity() is Some and wake the connection task, mirroring
release_capacity.

Validation:
New h2-tests case client_decrease_initial_window_size_sends_released_capacity
times out waiting for the WINDOW_UPDATE on master and passes with the fix.
cargo test -p h2-tests, cargo test -p h2 --lib, fmt and clippy pass.

Fixes hyperium#976

This branch has not been deployed

No deployments
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.

Receive flow-control stall after SETTINGS ACK shrinks the window with previously released capacity

1 participant