[PR #13356/72eaa429 backport][3.14] Stop handing back pipelined requests the parser buffered - #13360
Merged
Dreamsorcerer merged 2 commits intoAug 9, 2026
Conversation
(cherry picked from commit 72eaa42)
5 tasks
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## 3.14 #13360 +/- ##
=======================================
Coverage 98.26% 98.26%
=======================================
Files 135 135
Lines 49184 49218 +34
Branches 2637 2639 +2
=======================================
+ Hits 48329 48363 +34
Misses 675 675
Partials 180 180
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. |
Merging this PR will not alter performance
Comparing Footnotes
|
Dreamsorcerer
deleted the
patchback/backports/3.14/72eaa429cf89b1e20212590f3e704444239569fb/pr-13356
branch
August 9, 2026 16:17
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This is a backport of PR #13356 as merged into master (72eaa42).
What do these changes do?
When the pipelined message queue fills, the pure-Python parser buffers the unparsed remainder in
self._tailand returns it (http_parser.py, queue-full break). The caller therefore holds a second copy of bytes the parser is already keeping, and the nextfeed_data()prepends the retained copy onto the returned one.data_received()discards the returned tail unless the request upgraded, so ordinary pipelining never notices.finish_response()stores it unconditionally, and that is the path taken when a handler answers anUpgrade:request with a normal response. Pipelining more requests than the queue holds behind such a request then makes the server either serve them repeatedly or grow the buffer by a copy of itself per handled request.Measured on this branch's parent, pure-Python parser, one upgrade request followed by 40 pipelined GETs in a single write:
The fix clears the returned buffer, which is exactly what the incomplete-request-line branch a few lines below already does. The C parser never returned the tail, so the duplication is pure-Python only, and the added parser test passes on the C backend before and after.
The second defect is not parser-specific.
finish_response()appends to the message queue without the pause bookkeepingdata_received()performs, so_msg_queue_pausedstaysFalse,start()never calls_resume_msg_queue_reading(), and nothing ever feeds the parser the remainder it kept. The requests past the queue limit simply go unanswered (33 of 41 above). This half affects the C parser too — arguably more cleanly, since before the fix the pure-Python duplicate kept_message_tailnon-empty and so kept pumping. Reverting both source files and running the new functional test under the C extensions fails on its 10s timeout. Pausing infinish_response()lets the existing drain resume them.Are there changes in behavior for the user?
Requests pipelined behind a declined upgrade past the queue limit are answered instead of being left buffered — that applies to both parsers. With the pure-Python parser they are additionally handled exactly once rather than repeatedly. No API change.
Is it a substantial burden for the maintainers to support this?
No. Five lines of parser change plus the queue-pause call that the neighbouring code path already makes, and both new tests fail without them.
Related issue number
None.
Checklist
CONTRIBUTORS.txt— already listedCHANGES/folderTest run
Both parser backends, C extensions built (
make cythonize+ editable install):Revert check, with the source changes reverted and the tests kept:
Under
AIOHTTP_NO_EXTENSIONS=1that functional test does not fail cleanly when reverted: the repeated dispatch keeps the loop busy and the test's own timeout never fires. With the C extensions there is no repeated dispatch, so it fails on the timeout as shown above. It passes in well under a second either way with the change applied.