Skip to content

Parse the request body before raising HttpParserUpgrade - #155

Open
Kludex wants to merge 1 commit into
MagicStack:masterfrom
Kludex:parse-body-before-upgrade
Open

Kludex wants to merge 1 commit into
MagicStack:masterfrom
Kludex:parse-body-before-upgrade

Conversation

@Kludex

@Kludex Kludex commented Oct 11, 2026

Copy link
Copy Markdown
Contributor

Fixes #124.

cb_on_headers_complete returns 1 whenever the upgrade flag is set. That tells llhttp to skip the body, so an upgrade request that has a body (e.g. Upgrade: h2c + Content-Length or chunked, which JDK's HttpClient and curl --http2 send by default) raises HttpParserUpgrade right after the headers. The body is lost, and the bytes after the offset are parsed as a new request.

llhttp already makes this decision itself in llhttp__after_headers_complete: it pauses right after the headers for upgrades without a body, CONNECT, and 101 responses, and otherwise parses the body and pauses after on_message_complete. Returning 0 lets it do that.

What changes:

  • An upgrade request with a body fires on_body and on_message_complete first. Then HttpParserUpgrade is raised with the offset after the body.
  • WebSocket handshakes (GET with no body), CONNECT, and 101 responses behave the same as before.

This matches the RFCs. A server may ignore Upgrade (RFC 9110 §7.8), and an h2c upgrade request's body has to be read as HTTP/1.1 before switching protocols (RFC 7540 §3.2).

I ran uvicorn's protocol test suite against this branch and it passes. It also fixes Kludex/uvicorn#2722.

AI Disclaimer

This PR was developed with the assistance of either Claude or Codex. I've reviewed and verified the changes.

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.

Bug report candidate: Uvicorn drops body with Upgrade: h2c + chunked" [Bug] Request body lost when Upgrade: h2c + Transfer-Encoding: chunked is used

1 participant