Skip to content

[pull] master from aio-libs:master - #785

Merged
pull[bot] merged 3 commits into
tj-python:masterfrom
aio-libs:master
Sep 29, 2026
Merged

pull[bot] merged 3 commits into
tj-python:masterfrom
aio-libs:master

Conversation

@pull

@pull pull Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

See Commits and Changes for more details.


Created by pull[bot] (v2.0.0-alpha.4)

Can you help keep this open source service alive? 💖 Please sponsor : )

…13855)

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

## What do these changes do?

A redirect `Location` that has the scheme of the current URL but no
`//`, such as `http:/path` or `http:path`, is now joined with the
current URL, as browsers and the WHATWG URL Standard resolve it.
Previously only a `Location` without a scheme was joined, so
`http:/example.com` was taken as an absolute URL without a host and
failed with `InvalidUrlRedirectClientError`.

This is needed for aio-libs/yarl#1937, where yarl reads
`http:example.com/` as `http://example.com/` in its default WHATWG mode.
Without the join, aiohttp would follow `Location: http:/example.com` to
the host `example.com`, while a browser stays on the current host.
`Location: http:///example.com` is left as it was (still rejected):
browsers read it as the host `example.com`, which `URL.join()` does not
do. The check for `//` normalizes the Location as URL parsers do
(surrounding C0 controls and spaces stripped, tabs and newlines dropped)
and reads a backslash like a slash, as browsers do for http and https.

`http:/example.com` is removed from the invalid URL test data: a request
to it is invalid with the released yarl but goes to `example.com` with
yarl#1937. As a redirect it now resolves on both.

## Are there changes in behavior for the user?

Yes. `Location: http:/path`, `http:path` and `http:/` now redirect to
that path on the current host instead of raising
`InvalidUrlRedirectClientError`.

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

No, it is one condition in the redirect handling.

## Related issue number

Needed by aio-libs/yarl#1937, whose "Aiohttp tests" job fails on
`http:/example.com` without it.

## 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: `AIOHTTP_NO_EXTENSIONS=1 pytest tests -n auto`, 4796 passed, 60
skipped, 14 xfailed, both with yarl master (f761c37) and with the
yarl#1937 branch.
Lint: black, isort, codespell passed; flake8 (E, F, W) passed when run
directly, because the local pre-commit flake8 hook fails to load
`flake8-requirements` (`pkg_resources` missing); mypy on
`aiohttp/client.py` reports the same unrelated errors as on master.
</details>
)

<!-- 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>
<!-- Thank you for your contribution! -->

## What do these changes do?

`test_gen_netloc_all` and `test_gen_netloc_no_port` build a URL with a
50-digit host. An upcoming yarl change parses a special-scheme host made
only of numbers as an IPv4 address in its default WHATWG mode, as
browsers do, and rejects this one as out of range. The tests now use the
same digits followed by `.test`, which keeps the point of the tests (a
long host in the `Host` header) and passes with every yarl version.

## Are there changes in behavior for the user?

No, test-only change.

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

No.

## Related issue number

Needed by aio-libs/yarl#1940. yarl CI runs the aiohttp suite against
master, 3.14 and 3.15, so this needs backports to both release branches.

## Checklist

- [x] I think the code is well written
- [x] Unit tests for the changes exist
- [ ] Documentation reflects the changes: N/A, test-only
- [ ] 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, pure Python (`AIOHTTP_NO_EXTENSIONS=1`), `pytest tests -n 8`:
4798 passed, 60 skipped, 14 xfailed against the yarl branch for
aio-libs/yarl#1940. The two changed tests pass with released yarl
1.25.1; the old versions fail with `ValueError` against the yarl branch.
Lint: pre-commit with `SKIP=flake8,yesqa` (the local flake8 hook cannot
load `flake8-requirements`); flake8 run directly on the file passed.
</details>
@pull pull Bot locked and limited conversation to collaborators Sep 29, 2026
@pull pull Bot added the ⤵️ pull label Sep 29, 2026
@pull
pull Bot merged commit 8c324e5 into tj-python:master Sep 29, 2026
7 checks passed
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant