Skip to content

[PR #13301/58bae08b backport][3.15] Add METH_QUERY and treat QUERY as an idempotent method - #13318

Open
rodrigobnogueira wants to merge 1 commit into
aio-libs:3.15from
rodrigobnogueira:patchback/backports/3.15/58bae08b7e4831c6c184fe22233bfc19941c700b/pr-13301
Open

[PR #13301/58bae08b backport][3.15] Add METH_QUERY and treat QUERY as an idempotent method#13318
rodrigobnogueira wants to merge 1 commit into
aio-libs:3.15from
rodrigobnogueira:patchback/backports/3.15/58bae08b7e4831c6c184fe22233bfc19941c700b/pr-13301

Conversation

@rodrigobnogueira

Copy link
Copy Markdown
Member

This is a backport of PR #13301 as merged into master (58bae08).

What do these changes do?

Follow-up to #13160, as requested in #13160 (comment).

#13174 fixed the parser half of that issue, so QUERY now arrives intact instead of <unknown>. The two remaining pieces (originally part of the closed #13167) never landed:

  1. aiohttp/hdrs.py gains METH_QUERY, alongside the other METH_* constants.
  2. aiohttp/client.py adds "QUERY" to IDEMPOTENT_METHODS, so a QUERY request is replayed when the server closes a keep-alive connection underneath it, the same as GET or PUT. RFC 10008 defines the method as both safe and idempotent (https://www.rfc-editor.org/info/rfc10008/#section-1-12), which is exactly the property that set encodes.

METH_QUERY is deliberately not added to METH_ALL. RouteDef.register() dispatches every METH_ALL member through getattr(router, "add_" + method.lower()), and UrlDispatcher has no add_query(), so adding it there would turn web.route("QUERY", ...) passed to add_routes() into an AttributeError. (METH_CONNECT and METH_TRACE are already in METH_ALL without matching add_* methods, so that path is broken for them today — out of scope here.)

Are there changes in behavior for the user?

Yes, one: a QUERY request that hits a keep-alive connection the server has just closed is now retried once instead of raising ServerDisconnectedError. That is the documented behavior for safe, idempotent methods, and QUERY qualifies. Everything else is additive — a new public constant.

Is it a substantial burden for the maintainers to support this?

No. It is one constant and one set member, with no new code paths; the retry logic itself is untouched.

Related issue number

Follows up #13160 (fixed for the parser by #13174). Reuses the hdrs.py/client.py hunks from the closed #13167, with the RFC URL amended to the form suggested in review there.

Checklist

  • I think the code is well written
  • Unit tests for the changes exist
  • Documentation reflects the changes — N/A, hdrs constants are not individually documented and the retry behavior is described generically
  • If you provide code modification, please add yourself to CONTRIBUTORS.txt — N/A, already listed
  • Add a new news fragment into the CHANGES/ folder
Test evidence

New test test_retry_persistent_connection_query_method sits alongside the existing test_retry_persistent_connection_lowercase_method, and follows the same shape: the handler force-closes the connection on the first request, and the test asserts the request is retried.

Passes with both parsers:

$ AIOHTTP_NO_EXTENSIONS=1 pytest tests/test_test_utils.py -k retry_persistent -v
tests/test_test_utils.py::test_disable_retry_persistent_connection PASSED
tests/test_test_utils.py::test_retry_persistent_connection_lowercase_method PASSED
tests/test_test_utils.py::test_retry_persistent_connection_query_method PASSED

$ pytest tests/test_test_utils.py -k retry_persistent -v   # C extensions built
tests/test_test_utils.py::test_disable_retry_persistent_connection PASSED
tests/test_test_utils.py::test_retry_persistent_connection_lowercase_method PASSED
tests/test_test_utils.py::test_retry_persistent_connection_query_method PASSED

Confirmed the test fails without the production change (reverting IDEMPOTENT_METHODS to its previous value makes it error with the connection dropped, no retry), so it is not vacuous.

Wider run, no regressions:

$ pytest tests/test_test_utils.py tests/test_client_session.py
148 passed, 1 skipped, 1 xfailed

black, isort and mypy are clean on the touched files.

@rodrigobnogueira rodrigobnogueira added the bot:chronographer:skip This PR does not need to include a change note label Aug 3, 2026
@codecov

codecov Bot commented Aug 3, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.27%. Comparing base (b9ff891) to head (7fb3d6e).
⚠️ Report is 2 commits behind head on 3.15.

Additional details and impacted files
@@           Coverage Diff           @@
##             3.15   #13318   +/-   ##
=======================================
  Coverage   98.27%   98.27%           
=======================================
  Files         136      136           
  Lines       49417    49432   +15     
  Branches     2666     2667    +1     
=======================================
+ Hits        48563    48579   +16     
  Misses        674      674           
+ Partials      180      179    -1     
Flag Coverage Δ
CI-GHA 98.28% <100.00%> (+<0.01%) ⬆️
OS-Linux 98.05% <100.00%> (+<0.01%) ⬆️
OS-Windows 95.73% <100.00%> (+<0.01%) ⬆️
OS-macOS 97.22% <100.00%> (+<0.01%) ⬆️
Py-3.10 97.38% <100.00%> (+<0.01%) ⬆️
Py-3.11 97.68% <100.00%> (+<0.01%) ⬆️
Py-3.12 97.76% <100.00%> (+<0.01%) ⬆️
Py-3.13 97.73% <100.00%> (-0.01%) ⬇️
Py-3.14 97.84% <100.00%> (-0.01%) ⬇️
Py-3.14t 96.84% <100.00%> (-0.01%) ⬇️
Py-pypy-3.11 96.66% <100.00%> (+<0.01%) ⬆️
VM-macos 97.22% <100.00%> (+<0.01%) ⬆️
VM-ubuntu 98.05% <100.00%> (+<0.01%) ⬆️
VM-windows 95.73% <100.00%> (+<0.01%) ⬆️
cython-coverage 38.51% <11.76%> (-0.01%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

@codspeed-hq

codspeed-hq Bot commented Aug 4, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 84 untouched benchmarks
⏩ 86 skipped benchmarks1


Comparing rodrigobnogueira:patchback/backports/3.15/58bae08b7e4831c6c184fe22233bfc19941c700b/pr-13301 (7fb3d6e) with 3.15 (b9ff891)

Open in CodSpeed

Footnotes

  1. 86 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@rodrigobnogueira
rodrigobnogueira marked this pull request as ready for review August 4, 2026 03:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bot:chronographer:skip This PR does not need to include a change note

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant