Skip to content

gh-150499: http.server: drain unread request body on persistent connections (RFC 7230 §6.3)#150508

Open
tonghuaroot wants to merge 1 commit into
python:mainfrom
tonghuaroot:gh-150499-drain-body
Open

gh-150499: http.server: drain unread request body on persistent connections (RFC 7230 §6.3)#150508
tonghuaroot wants to merge 1 commit into
python:mainfrom
tonghuaroot:gh-150499-drain-body

Conversation

@tonghuaroot
Copy link
Copy Markdown

Closes gh-150499 (paired with #150500 which lands the §3.3.3 rules).

Summary

After #150500 lands the §3.3.3 rule-3 / rule-4 rejections, requests
that make it past parse_request may still carry an unread declared
body that the handler does not consume. Per RFC 7230 §6.3 the server
must either drain it or close the connection. Without that, the next
iteration of the keep-alive loop parses the leftover bytes as a
request line.

handle_one_request now wraps self.rfile with a small byte-counting
reader for the duration of the request. After the handler returns,
any unread declared body is drained up to a 1 MiB cap; over the cap
the connection is closed instead.

The wrapper proxies read, read1, readline, readinto, and
readinto1 and falls back to __getattr__ for everything else, so
existing handlers (including the ServerHandler chain in
wsgiref.simple_server, which passes self.rfile directly to WSGI
applications) continue to work unchanged.

Tests

Lib/test/test_httpservers.py adds RFC7230BodyDrainTestCase with
test_body_drained_on_persistent_connection, asserting the leftover
body is not parsed as the next request line on a persistent
connection. Full test_httpservers (103 tests) and test_wsgiref
(38 tests) suites also pass with no regression.

News entry

Misc/NEWS.d/next/Library/2026-05-27-09-15-22.gh-issue-150499.dBoDr4.rst.

Backport

This PR targets main only.

… connections

Follow-up to pythongh-150499 (paired with python#150500 which lands the §3.3.3
rules). Wrap rfile with a small byte-counting reader for the duration
of the request and, after the handler returns, drain any unread
declared body up to a 1 MiB cap (or close the connection if the
remainder is larger). Without this, the next iteration of the
keep-alive loop parses the leftover body as a request line, per RFC
7230 section 6.3.

The wrapper proxies read, read1, readline, readinto, and readinto1 and
falls back to __getattr__ for everything else, so existing handlers
(including the ServerHandler chain in wsgiref.simple_server, which
passes self.rfile directly to WSGI applications) continue to work
unchanged.

Add RFC7230BodyDrainTestCase asserting that the leftover body is not
parsed as the next request line on a persistent connection.

Signed-off-by: tonghuaroot <tonghuaroot@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

http.server: BaseHTTPRequestHandler does not enforce RFC 7230 framing validation (3 defects, hardening for keep-alive)

1 participant