From 876f7a482fbfec6025c93cce9c79c828e649b9ed Mon Sep 17 00:00:00 2001 From: Julian Soreavis <263610811+soreavis@users.noreply.github.com> Date: Mon, 13 Jul 2026 10:38:09 +0200 Subject: [PATCH 1/2] gh-153648: Deprecate http.client.HTTPMessage.getallmatchingheaders() getallmatchingheaders() has returned an empty list for every input since Python 3.0 -- it compares keys() entries, which are bare header names, against "name:". Its only user was the CGI handler, removed in 3.15, and run_cgi() had already stopped calling it in 3.10. Deprecate it, with removal in 3.18. Use email.message.Message.get_all() instead. --- Doc/deprecations/pending-removal-in-3.18.rst | 7 +++++++ Doc/whatsnew/3.16.rst | 9 +++++++++ Lib/http/client.py | 9 +++++++-- Lib/test/test_httplib.py | 6 ++++++ .../2026-07-13-08-20-16.gh-issue-153648.0L8KTV.rst | 4 ++++ 5 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-13-08-20-16.gh-issue-153648.0L8KTV.rst diff --git a/Doc/deprecations/pending-removal-in-3.18.rst b/Doc/deprecations/pending-removal-in-3.18.rst index 19113aab981bbc..8ff202f9466c71 100644 --- a/Doc/deprecations/pending-removal-in-3.18.rst +++ b/Doc/deprecations/pending-removal-in-3.18.rst @@ -16,3 +16,10 @@ Pending removal in Python 3.18 * ``import`` lines in :file:`{name}.pth` files are silently ignored. (Contributed by Barry Warsaw in :gh:`148641`.) + +* :mod:`http.client`: + + * :meth:`!http.client.HTTPMessage.getallmatchingheaders` has been deprecated + since Python 3.16. It has returned an empty list for every input since + Python 3.0; use :meth:`email.message.Message.get_all` instead. + (Contributed by Julian Soreavis in :gh:`153648`.) diff --git a/Doc/whatsnew/3.16.rst b/Doc/whatsnew/3.16.rst index da98f1ad6b9bc3..451722c0a42ab3 100644 --- a/Doc/whatsnew/3.16.rst +++ b/Doc/whatsnew/3.16.rst @@ -657,6 +657,15 @@ New deprecations 3.9, now issues a deprecation warning on use. This property is slated for removal in 3.21. Use ``ast.Tuple.elts`` instead. +* :mod:`http.client`: + + * :meth:`!http.client.HTTPMessage.getallmatchingheaders` is now deprecated + and will be removed in Python 3.18. It has returned an empty list for + every input since Python 3.0, and its only user, the CGI handler, was + removed in Python 3.15. Use :meth:`email.message.Message.get_all` + instead. + (Contributed by Julian Soreavis in :gh:`153648`.) + * :mod:`struct`: * Soft-deprecated since Python 3.15, using ``'F'`` and ``'D'`` type codes are now diff --git a/Lib/http/client.py b/Lib/http/client.py index 7ef99e7201c005..3b4f4f94e2b254 100644 --- a/Lib/http/client.py +++ b/Lib/http/client.py @@ -195,8 +195,8 @@ def _strip_ipv6_iface(enc_name: bytes) -> bytes: class HTTPMessage(email.message.Message): # The getallmatchingheaders() method was only used by the CGI handler - # that was removed in Python 3.15. However, since the public API was not - # properly defined, it will be kept for backwards compatibility reasons. + # that was removed in Python 3.15. It has returned an empty list for every + # input since Python 3.0. def getallmatchingheaders(self, name): """Find all header lines matching a given header name. @@ -208,6 +208,11 @@ def getallmatchingheaders(self, name): occurrences are returned. Case is not important in the header name. """ + import warnings + warnings._deprecated( + "http.client.HTTPMessage.getallmatchingheaders", + remove=(3, 18), + ) name = name.lower() + ':' n = len(name) lst = [] diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py index 5b1d6e0aa52079..a65661131557c1 100644 --- a/Lib/test/test_httplib.py +++ b/Lib/test/test_httplib.py @@ -507,6 +507,12 @@ def test_max_connection_trailers(self): response = conn.getresponse() self.assertEqual(response.read(), chunked_expected) + def test_getallmatchingheaders_deprecated(self): + message = client.parse_headers(io.BytesIO(b"Set-Cookie: a=1\r\n\r\n")) + with self.assertWarns(DeprecationWarning): + message.getallmatchingheaders("Set-Cookie") + + class HttpMethodTests(TestCase): def test_invalid_method_names(self): methods = ( diff --git a/Misc/NEWS.d/next/Library/2026-07-13-08-20-16.gh-issue-153648.0L8KTV.rst b/Misc/NEWS.d/next/Library/2026-07-13-08-20-16.gh-issue-153648.0L8KTV.rst new file mode 100644 index 00000000000000..777db65be895c0 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-13-08-20-16.gh-issue-153648.0L8KTV.rst @@ -0,0 +1,4 @@ +Deprecate :meth:`!http.client.HTTPMessage.getallmatchingheaders`, to be +removed in Python 3.18. It has returned an empty list for every input since +Python 3.0, and its only user, the CGI handler, was removed in Python 3.15. +Use :meth:`email.message.Message.get_all` instead. Patch by Julian Soreavis. From f2488f98c7a099f4396bf988aa751bea2ba0e844 Mon Sep 17 00:00:00 2001 From: Julian Soreavis <263610811+soreavis@users.noreply.github.com> Date: Mon, 13 Jul 2026 14:49:51 +0200 Subject: [PATCH 2/2] Point at get_all() in the deprecation warning --- Lib/http/client.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Lib/http/client.py b/Lib/http/client.py index 3b4f4f94e2b254..92a1b5c316bb38 100644 --- a/Lib/http/client.py +++ b/Lib/http/client.py @@ -211,6 +211,10 @@ def getallmatchingheaders(self, name): import warnings warnings._deprecated( "http.client.HTTPMessage.getallmatchingheaders", + message=( + "{name!r} is deprecated and slated for removal in Python " + "{remove}. Use email.message.Message.get_all() instead." + ), remove=(3, 18), ) name = name.lower() + ':'