Skip to content

gh-158182: http.client: don't assert on non-IPv6-zone percent-encoding in putrequest's netloc - #158184

Open
not-ekalabya wants to merge 1 commit into
python:mainfrom
not-ekalabya:fix-httpclient-ipv6-iface-assert
Open

not-ekalabya wants to merge 1 commit into
python:mainfrom
not-ekalabya:fix-httpclient-ipv6-iface-assert

Conversation

@not-ekalabya

Copy link
Copy Markdown

Description

Fixes #158182.

_strip_ipv6_iface() is meant to strip an IPv6 zone id from a bracketed
literal like [fe80::1%eth0], but HTTPConnection.putrequest() passes it
the entire netloc of an absolute-URL request -- the normal shape for
HTTP-proxy requests, which is exactly what urllib.request uses when
going through a proxy. Any RFC 3986-legal percent-encoding earlier in the
netloc than an IPv6 zone id -- most plausibly percent-encoded userinfo,
which is required whenever a username or password contains @, :,
/, or % -- made the function's assert enc_name.startswith(b'[') fail,
raising a raw AssertionError instead of sending the request.

The fix only treats the input as a bracketed IPv6 literal (and strips the
zone id) when it actually starts with [; otherwise it's returned
unchanged. This also fixes the case the original assertion was meant to
guard against when both userinfo and a zone id are present (e.g.
user%41@[fe80::1%eth0]/), since the previous code partitioned on the
userinfo's % first and never reached the real zone id.

I kept this fix scoped to the crash. There's a separate, arguably more
correct improvement -- stripping userinfo from the netloc entirely before
generating the Host header, since RFC 7230 forbids userinfo in Host
regardless -- which I left out to keep this PR minimal; happy to add it if
you'd rather have both in one PR.

Found via

Found via an automated code-review pass using GLM-5.3-flash paired with
scopegrep, a semantic code-retrieval tool; independently re-verified and
fixed by hand.

Testing

Same environment limitation as gh-158181/#158183: this environment's
installed Python is 3.12, and main's stdlib can't be imported/parsed by it
directly, so I could not run Lib/test/test_httplib.py. I verified with a
standalone harness loading Lib/http/client.py via importlib:

  • All three inputs that previously raised AssertionError (percent-encoded
    userinfo, percent-encoded hostname) now return the netloc unchanged.
  • The existing test_ipv6host_header test's four assertions
    ([2001::]:81, [2001:102A::], [fe80::%2] -> [fe80::],
    [fe80::%2]:81 -> [fe80::]:81) were manually re-run against the fixed
    module and still pass exactly as before -- no regression to the actual
    IPv6-zone-stripping behavior this function exists for.

Please run the real test suite as part of review, since I could not do so
myself here.

Drafted with Claude Sonnet 5 (Anthropic); reviewed by @not-ekalabya before merge.

…ent-encoded netloc

_strip_ipv6_iface() is meant to strip an IPv6 zone id from a bracketed
literal like [fe80::1%eth0], but putrequest() passes it the entire
netloc of an absolute-URL request (the normal shape for HTTP-proxy
requests). Any RFC 3986-legal percent-encoding earlier in the netloc
than a zone id -- most plausibly percent-encoded userinfo, required
whenever a username or password contains '@', ':', '/', or '%' --
made the function assert that the part before the first '%' starts
with '[', raising a raw AssertionError instead of sending the request.

Only treat the input as a bracketed IPv6 literal (and strip the zone
id) when it actually starts with '['; otherwise return it unchanged.
This also fixes the case the assertion was meant to guard when both
userinfo and a zone id are present, since the previous code partitioned
on the userinfo's '%' first.
@python-cla-bot

python-cla-bot Bot commented Sep 25, 2026 •

Copy link
Copy Markdown

All commit authors signed the Contributor License Agreement.

CLA signed

@@ -0,0 +1,3 @@
Fix :exc:`AssertionError` in :meth:`http.client.HTTPConnection.putrequest`
when an absolute-URL request's netloc contains RFC 3986 percent-encoding

Copy link
Copy Markdown

Choose a reason for hiding this comment

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


Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

http.client: AssertionError in putrequest() on an absolute-URL netloc with percent-encoded userinfo

2 participants