diff --git a/Lib/http/client.py b/Lib/http/client.py index 7ef99e7201c005..7dbdc8e496c13f 100644 --- a/Lib/http/client.py +++ b/Lib/http/client.py @@ -186,11 +186,16 @@ def _encode(data, name='data'): def _strip_ipv6_iface(enc_name: bytes) -> bytes: """Remove interface scope from IPv6 address.""" - enc_name, percent, _ = enc_name.partition(b"%") - if percent: - assert enc_name.startswith(b'['), enc_name - enc_name += b']' - return enc_name + before, percent, after = enc_name.partition(b"%") + if not percent or not before.startswith(b'['): + # No '%' in the input, or it's not a bracketed IPv6 literal, so + # this isn't an IPv6 zone id -- e.g. RFC 3986 percent-encoding + # elsewhere in the netloc, most plausibly in userinfo (required + # whenever a username/password contains '@', ':', '/', or '%'). + # Leave it untouched rather than assuming the '%' we happened to + # find is a zone separator. + return enc_name + return before + b']' class HTTPMessage(email.message.Message): diff --git a/Misc/NEWS.d/next/Library/2026-09-25-17-43-30.gh-issue-158182.2MgwWD.rst b/Misc/NEWS.d/next/Library/2026-09-25-17-43-30.gh-issue-158182.2MgwWD.rst new file mode 100644 index 00000000000000..61188bed774fcf --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-09-25-17-43-30.gh-issue-158182.2MgwWD.rst @@ -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 +outside of an IPv6 zone identifier, such as percent-encoded userinfo.