cpython/Lib/urllib
Miss Islington (bot) 7ed5a4f3cb
[3.14] gh-59515: Support multiple challenges in urllib Digest Auth (GH-160828) (#161161)
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 529d66cf2f)

Co-authored-by: Senthil Kumaran <senthil@python.org>
2026-11-02 08:49:47 +00:00
..
__init__.py
error.py
parse.py
request.py [3.14] gh-59515: Support multiple challenges in urllib Digest Auth (GH-160828) (#161161) 2026-11-02 08:49:47 +00:00
response.py
robotparser.py