Skip to content

Keep client handshakes pending after interim HTTP responses - #206

Open
AryanRG wants to merge 1 commit into
python-hyper:mainfrom
AryanRG:fix/interim-handshake-responses
Open

AryanRG wants to merge 1 commit into
python-hyper:mainfrom
AryanRG:fix/interim-handshake-responses

Conversation

@AryanRG

@AryanRG AryanRG commented Oct 16, 2026 •

Copy link
Copy Markdown

A client currently treats a provisional HTTP response such as 103 Early Hints as a rejected upgrade and moves to CLOSED. If the 101 arrives in the same read, callers instead receive a spurious RejectConnection before AcceptConnection.

Keep the handshake pending for informational responses other than 101. RFC 6455 section 4.1 delegates non-101 responses to HTTP procedures, and RFC 9110 section 15.2 requires clients to handle interim responses before the final response:

The existing 101 validation and final HTTP rejection paths are unchanged. Replace the test that expected a 102 rejection with coverage for multiple interim responses, statuses 100/102/103/199, separate/coalesced reads, and final 101/403 responses. Update the affected event documentation and changelog.

Minimal reproduction on the base revision:

from wsproto import WSConnection
from wsproto.connection import CLIENT
from wsproto.events import Request

client = WSConnection(CLIENT)
client.send(Request(host="localhost", target="/"))
client.receive_data(b"HTTP/1.1 103 Early Hints\r\n\r\n")
print(client.state, list(client.events()))

Before: CLOSED and a RejectConnection(status_code=103, has_body=False) event. After: CONNECTING and no events, waiting for the upgrade or final HTTP response.

Validation on macOS/CPython 3.13.12:

  • Original suite: 230 passed.
  • New focused regression: 16 failed before the fix; 16 passed after it.
  • Full suite with python -bb -m pytest --cov=wsproto --cov-report=term --cov-report=xml: 245 passed, total coverage unchanged at 97%.
  • Strict mypy src/, Sphinx HTML build, and git diff --check: passed.
  • The new regression function passes Ruff's formatter check. Ruff lint findings in the changed handshake/client files are unchanged from the base; Ruff lint is commented out in the current tox configuration. Whole-file formatting also reports existing differences outside the new function.
  • Independent AI review: APPROVE, with independent reproduction of the 16 failures and a 245-test passing run. Extra probes covered byte-fragmented reads, trailing WebSocket data, streaming rejection bodies, and invalid accept tokens after interim responses.

Other Python versions and platforms have not been tested locally. Hosted CI and maintainer review remain pending.

AI disclosure: AI agents investigated the bug, wrote the patch and regression tests, ran the checks, and drafted this PR. A separate AI agent performed an automated review of the patch. Maintainer review is requested.

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.

1 participant