Skip to content

Acknowledge HTTP/2 data received for an already closed stream - #391

Open
mayuriphad wants to merge 1 commit into
pgjones:mainfrom
mayuriphad:fix/h2-data-after-stream-closed
Open

mayuriphad wants to merge 1 commit into
pgjones:mainfrom
mayuriphad:fix/h2-data-after-stream-closed

Conversation

@mayuriphad

Copy link
Copy Markdown

Fixes #389

When an ASGI app responds without reading the whole request body, the client keeps sending the rest of the body over HTTP/2. Once Hypercorn has closed the stream, the next DataReceived event for it hits self.streams[event.stream_id] and raises KeyError. That error escapes TCPServer._read_data, so the connection's reader stops while the socket stays open, and every later request on that connection hangs. Behind a proxy that multiplexes many clients over one h2c connection, one early-answered upload stalls unrelated requests.

The StreamEnded branch right below already ignores a stream that is gone. DataReceived now does the same, but it still calls acknowledge_received_data, so the connection-level flow-control window is given back and the client can keep sending on other streams.

The fix is the one @iker-gonzalez suggested in the issue, so they are credited as co-author.

Tests

  • New test_protocol_data_received_after_stream_closed in tests/protocol/test_h2.py: it closes the stream after the request headers, sends three DATA frames for it, and checks that no error is raised and that the client gets a connection-level WindowUpdated. It fails with KeyError: 1 without the change.
  • The rest of the suite (minus the trio-based modules, since trio isn't installed here) gives the same result before and after: 3 failures that also happen on unmodified main on Windows, and the new test passes.
  • black -l 100, isort and flake8 are clean on the changed files.

If an app sends its response without reading the whole request body,
the client keeps sending the rest of the body. Once the stream has been
closed, the next DataReceived event raised a KeyError, which stopped the
connection's reader and left every later request on that connection
hanging.

Drop the data, as the StreamEnded branch already does, but still
acknowledge it so the connection-level flow-control window is restored.

Fixes pgjones#389

Co-authored-by: iker-gonzalez <84924263+iker-gonzalez@users.noreply.github.com>
Signed-off-by: mayuriphad <mayuriphad656@gmail.com>
Copilot AI balanced review requested due to automatic review settings October 30, 2026 15:45

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.

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.

HTTP/2: DataReceived for an already-closed stream raises KeyError and wedges the connection

2 participants