[PR #13858/ce960dd1 backport][3.15] Reject absolute-form targets without an authority before parsing by patchback[bot] · Pull Request #13859 · aio-libs/aiohttp · GitHub
Skip to content

[PR #13858/ce960dd1 backport][3.15] Reject absolute-form targets without an authority before parsing - #13859

Merged
asvetlov merged 1 commit into
3.15from
patchback/backports/3.15/ce960dd17e34f143762c14c32b9e14435ea7ce11/pr-13858
Sep 29, 2026
Merged

asvetlov merged 1 commit into
3.15from
patchback/backports/3.15/ce960dd17e34f143762c14c32b9e14435ea7ce11/pr-13858

Conversation

@patchback

@patchback patchback Bot commented Sep 29, 2026

Copy link
Copy Markdown
Contributor

This is a backport of PR #13858 as merged into master (ce960dd).

What do these changes do?

Follow-up to #13855 for aio-libs/yarl#1937. With that change, yarl's default WHATWG mode reads a host from http:host/p, http:/host/p and http:///host/p, as browsers do. The Python and Cython request parsers passed an absolute-form request target to URL() and rejected it only if yarl found no host. They now first check that the target has // followed by a non-empty authority, so GET http:///protected and GET http:/protected stay rejected as RFC 9110 requires, whatever yarl version is installed.

The client tests used http:///example.com and http:///path as URLs without a host. They now use http:// where an invalid URL is needed, and http:///example.com is dropped from the invalid URL test data. With yarl#1937 it is http://example.com/, and as a redirect it leads to example.com, as in browsers.

Are there changes in behavior for the user?

No with the released yarl, where such targets were already rejected. With yarl#1937, the server keeps rejecting absolute-form targets without an authority instead of reading a host from them.

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

No, it is one string check shared by both parsers.

Related issue number

Follow-up to #13855; needed by aio-libs/yarl#1937.

Checklist

  • I think the code is well written
  • Unit tests for the changes exist
  • Documentation reflects the changes: N/A, no documented behavior changes
  • If you provide code modification, please add yourself to CONTRIBUTORS.txt: N/A, already listed
  • Add a new news fragment into the CHANGES/ folder

Drafted with Claude Code (Claude Opus 5.5); reviewed by @asvetlov.

Agent run details (optional, for reviewers)

Tests with the Cython extensions built (llhttp generated, make cythonize, build_ext --inplace): pytest tests -n auto, 5246 passed, 22 skipped, 17 xfailed, both with yarl master (f761c37) and with the yarl#1937 branch (8d0f111). Pure-Python run of test_http_parser.py, test_client_functional.py and test_client_session.py with the yarl#1937 branch: 884 passed.
Lint: black, isort, codespell passed. The local pre-commit flake8 hook fails to load flake8-requirements (pkg_resources missing), so flake8 (E, F, W) was run directly and passed. yesqa was skipped for the same reason, because it wrongly strips # noqa: I900.

)

<!-- Thank you for your contribution! -->

## What do these changes do?

Follow-up to #13855 for aio-libs/yarl#1937. With that change, yarl's
default WHATWG mode reads a host from `http:host/p`, `http:/host/p` and
`http:///host/p`, as browsers do. The Python and Cython request parsers
passed an absolute-form request target to `URL()` and rejected it only
if yarl found no host. They now first check that the target has `//`
followed by a non-empty authority, so `GET http:///protected` and `GET
http:/protected` stay rejected as RFC 9110 requires, whatever yarl
version is installed.

The client tests used `http:///example.com` and `http:///path` as URLs
without a host. They now use `http://` where an invalid URL is needed,
and `http:///example.com` is dropped from the invalid URL test data.
With yarl#1937 it is `http://example.com/`, and as a redirect it leads
to `example.com`, as in browsers.

## Are there changes in behavior for the user?

No with the released yarl, where such targets were already rejected.
With yarl#1937, the server keeps rejecting absolute-form targets without
an authority instead of reading a host from them.

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

No, it is one string check shared by both parsers.

## Related issue number

Follow-up to #13855; needed by aio-libs/yarl#1937.

## Checklist

- [x] I think the code is well written
- [x] Unit tests for the changes exist
- [ ] Documentation reflects the changes: N/A, no documented behavior
changes
- [ ] If you provide code modification, please add yourself to
`CONTRIBUTORS.txt`: N/A, already listed
- [x] Add a new news fragment into the `CHANGES/` folder

Drafted with Claude Code (Claude Opus 5.5); reviewed by @asvetlov.

<details>
<summary>Agent run details (optional, for reviewers)</summary>

Tests with the Cython extensions built (llhttp generated, `make
cythonize`, `build_ext --inplace`): `pytest tests -n auto`, 5246 passed,
22 skipped, 17 xfailed, both with yarl master (f761c37) and with the
yarl#1937 branch (8d0f111). Pure-Python run of `test_http_parser.py`,
`test_client_functional.py` and `test_client_session.py` with the
yarl#1937 branch: 884 passed.
Lint: black, isort, codespell passed. The local pre-commit flake8 hook
fails to load `flake8-requirements` (`pkg_resources` missing), so flake8
(E, F, W) was run directly and passed. yesqa was skipped for the same
reason, because it wrongly strips `# noqa: I900`.
</details>

(cherry picked from commit ce960dd)
@codecov

codecov Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

@greptile-apps

greptile-apps Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 5/5

[Critical risk] HTTP request parser rejects malformed absolute-form targets.

No blocking issue was established; the reviewed changes appear safe to merge.

What we checked:

  • Ran 32 adversarial authority request probes against the base and PR revisions; both runs exited successfully and showed the empty wire authority prevents routing while valid targets preserve the expected host. T-Rex
  • Ran representative valid absolute-form target tests against both revisions; IPv6 hosts, credentials, mixed-case schemes parsed and returned HTTP 200, while the empty-authority control returned HTTP 400. T-Rex
  • Executed redirects to a local reproduction and explicit requests, plus a local control endpoint, on both revisions; both revisions rejected the invalid URL redirects and explicit URLs, while the control endpoint returned HTTP 200. T-Rex
  • Compared end-to-end results across both revisions; all valid targets parsed and returned HTTP/1.1 200 OK with the body proxy target accepted, while the empty-authority target produced HTTP/1.0 400, and the build did not observe the anticipated WHATWG host-recovery behavior for that future mode. T-Rex
  • Verified redirect-following behavior under different configurations; with following disabled, responses were HTTP 301, and with following enabled, InvalidUrlRedirectClientError or InvalidUrlClientError were raised before reaching another endpoint, while the control endpoint remained HTTP 200 OK. T-Rex

Reviews (1) · Last reviewed commit: "Reject absolute-form targets without an ..."

@codspeed

codspeed Bot commented Sep 29, 2026

Copy link
Copy Markdown

@asvetlov
asvetlov merged commit 67974c9 into 3.15 Sep 29, 2026
53 of 54 checks passed
@asvetlov
asvetlov deleted the patchback/backports/3.15/ce960dd17e34f143762c14c32b9e14435ea7ce11/pr-13858 branch September 29, 2026 09:22
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