mirror of
https://github.com/python/cpython
synced 2026-11-06 09:02:40 +03:00
gh-59515: Support multiple challenges in urllib Digest Auth (GH-160828)
`HTTPDigestAuthHandler` and `ProxyDigestAuthHandler` only looked at the
first `WWW-Authenticate` / `Proxy-Authenticate` header and took its
first word as the scheme. As a result:
* A Digest challenge was ignored if a Basic challenge came first, in the
same header or in an earlier one.
* An unsupported scheme listed first (for example `Kerberos, Basic
realm="x"`) raised `ValueError`. Because the Digest handler runs
before the Basic handler, that also blocked `HTTPBasicAuthHandler`.
This PR changes only `AbstractDigestAuthHandler`.
`AbstractBasicAuthHandler` already handles multiple challenges since
GH-18284 and is not modified.
* `http_error_auth_reqed()` now reads all headers (`get_all()`) and uses
the first Digest challenge found. It raises `ValueError` only when
neither Digest nor Basic is offered; otherwise it returns `None` so
the next handler can try.
* A new private `_parse_challenges()` splits a header into challenges
per RFC 9110 §11.6.1. A comma-separated element that starts with a
word not followed by `=` begins a new challenge. Its quote/escape
handling matches `parse_http_list()`. It makes a single linear pass
with no regex.
* `retry_http_digest_auth()` is unchanged. It receives the original text
of the Digest challenge, so escapes are not processed twice. For a
single-challenge header the string is the same as before.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
(cherry picked from commit
|
||
|---|---|---|
| .. | ||
| __init__.py | ||
| error.py | ||
| parse.py | ||
| request.py | ||
| response.py | ||
| robotparser.py | ||