diff --git a/Lib/test/test_wsgiref.py b/Lib/test/test_wsgiref.py index 484a2db1637861c..e0225bdec2eb493 100644 --- a/Lib/test/test_wsgiref.py +++ b/Lib/test/test_wsgiref.py @@ -592,6 +592,19 @@ def testMappingInterface(self): self.assertEqual(h["foo"],"baz") self.assertEqual(h["zoo"],"whee") + def testSetItemValidationFailureKeepsOldValue(self): + # gh-158225: __setitem__ must not delete the old header + # before validating the new name and value. + for bad_value, exc_type in [ + ("bad\x00value", ValueError), + (123, AssertionError), + ]: + with self.subTest(bad_value=bad_value): + h = Headers([("Content-Type", "text/html")]) + with self.assertRaises(exc_type): + h["Content-Type"] = bad_value + self.assertEqual(h["Content-Type"], "text/html") + def testRequireList(self): self.assertRaises(TypeError, Headers, "foo") diff --git a/Lib/wsgiref/headers.py b/Lib/wsgiref/headers.py index eb6ea6a412dcc90..a27eec3a7dbb363 100644 --- a/Lib/wsgiref/headers.py +++ b/Lib/wsgiref/headers.py @@ -59,11 +59,12 @@ def __len__(self): def __setitem__(self, name, val): """Set the value of a header.""" + name = self._convert_string_type(name, name=True) + val = self._convert_string_type(val, name=False) del self[name] - self._headers.append( - (self._convert_string_type(name, name=True), self._convert_string_type(val, name=False))) + self._headers.append((name, val)) - def __delitem__(self,name): + def __delitem__(self, name): """Delete all occurrences of a header, if present. Does *not* raise an exception if the header is missing. diff --git a/Misc/NEWS.d/next/Library/2026-09-26-17-24-55.gh-issue-158225.AbCdEf.rst b/Misc/NEWS.d/next/Library/2026-09-26-17-24-55.gh-issue-158225.AbCdEf.rst new file mode 100644 index 000000000000000..48121c5e4ac2bb7 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-09-26-17-24-55.gh-issue-158225.AbCdEf.rst @@ -0,0 +1,3 @@ +Fix :class:`wsgiref.headers.Headers` so that ``__setitem__`` keeps the +existing header value when validation of the new value fails. Patch by +Tony Leung.