From 6a1628aece05e4a6b6950528ae058ba1f6c53e32 Mon Sep 17 00:00:00 2001 From: Nikolaus Schuetz Date: Sun, 12 Jul 2026 10:10:45 -0700 Subject: [PATCH] gh-154317: Add test for parse_qsl/parse_qs strict_parsing on malformed fields The strict_parsing=True path in urllib.parse.parse_qsl and parse_qs was only exercised with empty inputs, which return before the parsing loop, so its ValueError branch was untested. Add tests that a field without "=" raises, whether it is a bare name or an empty field (from a doubled, leading, or trailing separator), for str and bytes. The empty-field case also covers the guard that stops strict mode from silently skipping empty fields. Assert the boundary too: a field is accepted whenever it contains "=", even with an empty name or value, and well-formed input still parses. --- Lib/test/test_urlparse.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/Lib/test/test_urlparse.py b/Lib/test/test_urlparse.py index a5b7966c7780e9e..26f120c8746695d 100644 --- a/Lib/test/test_urlparse.py +++ b/Lib/test/test_urlparse.py @@ -1527,6 +1527,34 @@ def test_parse_qsl_false_value(self): self.assertEqual(cm.filename, __file__) self.assertRaises(ValueError, urllib.parse.parse_qsl, x, separator=1) + def test_parse_qsl_strict_parsing(self): + self.assertRaises(ValueError, urllib.parse.parse_qsl, + 'a=1&b&c=3', strict_parsing=True) + self.assertRaises(ValueError, urllib.parse.parse_qsl, + b'a=1&b', strict_parsing=True) + self.assertRaises(ValueError, urllib.parse.parse_qs, + 'a=1&b&c=3', strict_parsing=True) + self.assertRaises(ValueError, urllib.parse.parse_qs, + b'a=1&b', strict_parsing=True) + self.assertRaises(ValueError, urllib.parse.parse_qsl, + 'a=1&&c=3', strict_parsing=True) + self.assertRaises(ValueError, urllib.parse.parse_qsl, + b'a=1&', strict_parsing=True) + self.assertRaises(ValueError, urllib.parse.parse_qs, + 'a=1&&c=3', strict_parsing=True) + self.assertRaises(ValueError, urllib.parse.parse_qs, + b'a=1&', strict_parsing=True) + self.assertEqual(urllib.parse.parse_qsl('a=1&c=3', strict_parsing=True), + [('a', '1'), ('c', '3')]) + self.assertEqual(urllib.parse.parse_qs('a=1&c=3', strict_parsing=True), + {'a': ['1'], 'c': ['3']}) + self.assertEqual(urllib.parse.parse_qsl('=abc', strict_parsing=True), + [('', 'abc')]) + self.assertEqual( + urllib.parse.parse_qsl( + 'abc=', strict_parsing=True, keep_blank_values=True), + [('abc', '')]) + def test_parse_qsl_errors(self): self.assertRaises(TypeError, urllib.parse.parse_qsl, list(b'a=b')) self.assertRaises(TypeError, urllib.parse.parse_qsl, iter(b'a=b'))