Skip to content

gh-47005: fix do_open() to let regular headers override unredirected …#146506

Merged
orsenthil merged 6 commits into
python:mainfrom
Das-Chinmay:fix-urllib-header-priority
Jul 9, 2026
Merged

gh-47005: fix do_open() to let regular headers override unredirected …#146506
orsenthil merged 6 commits into
python:mainfrom
Das-Chinmay:fix-urllib-header-priority

Conversation

@Das-Chinmay

Copy link
Copy Markdown
Contributor

AbstractHTTPHandler.do_open() builds the outgoing header dict by starting
with unredirected_hdrs and only merging regular headers that are not
already present — giving unredirected headers the higher priority.

This contradicts both get_header() (checks self.headers first) and
header_items() ({**unredirected_hdrs, **headers}), which both give
regular headers priority. The result: a header set via add_header() is
silently ignored if the same name was already set via add_unredirected_header().

Fix: replace the conditional merge with an unconditional headers.update(req.headers).

Fixes gh-47005

@bedevere-app

bedevere-app Bot commented Mar 27, 2026

Copy link
Copy Markdown

Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool.

If this change has little impact on Python users, wait for a maintainer to apply the skip news label instead.

@github-actions

github-actions Bot commented May 9, 2026

Copy link
Copy Markdown

This PR is stale because it has been open for 30 days with no activity.

@github-actions github-actions Bot added the stale Stale PR or inactive for long period of time. label May 9, 2026
@orsenthil orsenthil removed the stale Stale PR or inactive for long period of time. label Jul 9, 2026
Das-Chinmay and others added 5 commits July 8, 2026 17:09
…ected headers

AbstractHTTPHandler.do_open() was building the request header dict by
starting with unredirected_hdrs and only inserting regular headers that
were not already present, giving unredirected headers priority.  This
contradicts get_header() and header_items(), both of which give regular
headers the higher priority.

Fix by unconditionally updating with req.headers so that a header set
via add_header() always overrides one set via add_unredirected_header().
Comment thread Lib/urllib/request.py
headers = dict(req.unredirected_hdrs)
headers.update({k: v for k, v in req.headers.items()
if k not in headers})
headers.update(req.headers)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change looks good to me and sufficient.
I am reviewing the rest of the discussion of this long open issue, and ensuring we will have enough tests.

@orsenthil orsenthil left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review noted inline.

@orsenthil orsenthil force-pushed the fix-urllib-header-priority branch from c8bd4af to f7eab12 Compare July 9, 2026 00:18
@orsenthil

Copy link
Copy Markdown
Member

I have reviewed the use cases of this long open bug.

Headers set using add_header() should not be ignored in favor of add_unredirected_header(). It breaks the expectation and in-consistent with other usages.

I was only worried if we will be breaking some existing use-case that relied on this faulty behavior. But the possibility of that seems very remote. When an user has explicitly set add_header we should just honor it.

The patch is simple and clean.

@orsenthil orsenthil left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@orsenthil orsenthil added needs backport to 3.13 bugs and security fixes needs backport to 3.14 bugs and security fixes needs backport to 3.15 pre-release feature fixes, bugs and security fixes labels Jul 9, 2026
@orsenthil orsenthil merged commit 6d38668 into python:main Jul 9, 2026
57 checks passed
@miss-islington-app

Copy link
Copy Markdown

Thanks @Das-Chinmay for the PR, and @orsenthil for merging it 🌮🎉.. I'm working now to backport this PR to: 3.13, 3.14, 3.15.
🐍🍒⛏🤖 I'm not a witch! I'm not a witch!

@bedevere-app

bedevere-app Bot commented Jul 9, 2026

Copy link
Copy Markdown

GH-153377 is a backport of this pull request to the 3.15 branch.

@bedevere-app bedevere-app Bot removed the needs backport to 3.15 pre-release feature fixes, bugs and security fixes label Jul 9, 2026
@bedevere-app

bedevere-app Bot commented Jul 9, 2026

Copy link
Copy Markdown

GH-153378 is a backport of this pull request to the 3.14 branch.

@bedevere-app bedevere-app Bot removed the needs backport to 3.14 bugs and security fixes label Jul 9, 2026
@bedevere-app

bedevere-app Bot commented Jul 9, 2026

Copy link
Copy Markdown

GH-153379 is a backport of this pull request to the 3.13 branch.

@bedevere-app bedevere-app Bot removed the needs backport to 3.13 bugs and security fixes label Jul 9, 2026
orsenthil added a commit that referenced this pull request Jul 9, 2026
…rected … (GH-146506) (#153379)

gh-47005: fix do_open() to let regular headers override unredirected … (GH-146506)

AbstractHTTPHandler.do_open() was building the request header dict by
starting with unredirected_hdrs and only inserting regular headers that
were not already present, giving unredirected headers priority.  This
contradicts get_header() and header_items(), both of which give regular
headers the higher priority.

Fix by unconditionally updating with req.headers so that a header set
via add_header() always overrides one set via add_unredirected_header().

---------
(cherry picked from commit 6d38668)

Co-authored-by: CHINMAY <89741289+Das-Chinmay@users.noreply.github.com>
Co-authored-by: Senthil Kumaran <senthil@python.org>
orsenthil added a commit that referenced this pull request Jul 9, 2026
…rected … (GH-146506) (#153377)

gh-47005: fix do_open() to let regular headers override unredirected … (GH-146506)

AbstractHTTPHandler.do_open() was building the request header dict by
starting with unredirected_hdrs and only inserting regular headers that
were not already present, giving unredirected headers priority.  This
contradicts get_header() and header_items(), both of which give regular
headers the higher priority.

Fix by unconditionally updating with req.headers so that a header set
via add_header() always overrides one set via add_unredirected_header().

---------
(cherry picked from commit 6d38668)

Co-authored-by: CHINMAY <89741289+Das-Chinmay@users.noreply.github.com>
Co-authored-by: Senthil Kumaran <senthil@python.org>
orsenthil added a commit that referenced this pull request Jul 9, 2026
…rected … (GH-146506) (#153378)

gh-47005: fix do_open() to let regular headers override unredirected … (GH-146506)

AbstractHTTPHandler.do_open() was building the request header dict by
starting with unredirected_hdrs and only inserting regular headers that
were not already present, giving unredirected headers priority.  This
contradicts get_header() and header_items(), both of which give regular
headers the higher priority.

Fix by unconditionally updating with req.headers so that a header set
via add_header() always overrides one set via add_unredirected_header().

---------
(cherry picked from commit 6d38668)

Co-authored-by: CHINMAY <89741289+Das-Chinmay@users.noreply.github.com>
Co-authored-by: Senthil Kumaran <senthil@python.org>
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.

urllib.request.add_header fails with existing unredirected_header

2 participants