Skip to content

Allow the QUERY method (RFC 10008) by default - #413

Draft
rpodgorny wants to merge 1 commit into
corydolphin:mainfrom
rpodgorny:add-query-method-rfc-10008
Draft

Allow the QUERY method (RFC 10008) by default#413
rpodgorny wants to merge 1 commit into
corydolphin:mainfrom
rpodgorny:add-query-method-rfc-10008

Conversation

@rpodgorny

Copy link
Copy Markdown

QUERY is the safe, idempotent method with a request body standardized in RFC 10008 (June 2026). It is not CORS-safelisted, so cross-origin use is preflighted, exactly like PUT, PATCH and DELETE.

Because QUERY was missing from ALL_METHODS, a preflight carrying Access-Control-Request-Method: QUERY fails the membership check in get_cors_headers (flask_cors/core.py:330), which drops the entire Access-Control-Allow-Methods header rather than emitting a list without QUERY. The browser then blocks the request, and the response gives no hint as to why.

Measured against flask-cors 6.0.5, same app, two preflights:

# CORS(app), Access-Control-Request-Method: QUERY
HTTP/1.0 200 OK
Access-Control-Allow-Origin: http://example.com
                                    <-- no Access-Control-Allow-Methods at all

# CORS(app), Access-Control-Request-Method: POST   (control)
HTTP/1.0 200 OK
Access-Control-Allow-Origin: http://example.com
Access-Control-Allow-Methods: DELETE, GET, HEAD, OPTIONS, PATCH, POST, PUT

Flask already routes methods=["QUERY"] and parses the body via request.get_json(), so the server side works today; only the CORS default was out of date. Browsers need no update either — QUERY is neither a forbidden nor a normalized method in the Fetch standard, so fetch(url, {method: 'QUERY', body}) and XMLHttpRequest already send it in current Chromium and Firefox. The CORS default is the remaining blocker for cross-origin use.

Changes

  • flask_cors/core.py — add QUERY to ALL_METHODS
  • flask_cors/decorator.py, flask_cors/extension.py — update the documented default in the methods docstrings
  • tests/decorator/test_methods.py — regression test asserting a default-config QUERY preflight gets Access-Control-Allow-Methods
  • CHANGELOG.md — entry under Unreleased

Checks

  • make test — 99 passed, 1 skipped
  • make check — mypy clean, deptry clean, lock file consistent
  • New test verified to fail without the core.py change (AssertionError: unexpectedly None)

Notes

Users on released versions can work around this today with an explicit list:

CORS(app, methods=["GET", "HEAD", "POST", "OPTIONS", "PUT", "PATCH", "DELETE", "QUERY"])

Two unrelated things noticed while following CONTRIBUTING, not addressed here:

  • The lint step in make check is a no-op — the pre-commit line in the Makefile is commented out (# @uv run pre-commit run -a).
  • Running pre-commit manually, the ruff hook fails on this repo's own pyproject.toml with Unknown rule selector: TC; the ruff version pinned in .pre-commit-config.yaml predates that selector.

Happy to adjust naming, test placement, or drop the code comment if you'd rather keep the constant bare.

🤖 Generated with Claude Code

QUERY is the safe, idempotent method with a request body standardized in
RFC 10008 (June 2026). It is not CORS-safelisted, so cross-origin use is
preflighted, exactly like PUT, PATCH and DELETE.

Because QUERY was missing from ALL_METHODS, a preflight carrying
`Access-Control-Request-Method: QUERY` failed the membership check in
get_cors_headers, which drops the entire Access-Control-Allow-Methods
header rather than emitting a list without QUERY. The browser then
blocked the request, and the response gave no hint as to why.

Flask already routes `methods=["QUERY"]` and parses the body, so the
server side works today; only the CORS default was out of date.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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