33import logging
44import sys
55import time
6- import typing
76from http .cookies import (
87 CookieError ,
98 Morsel ,
109 SimpleCookie ,
1110 _unquote as simplecookie_unquote ,
1211)
13- from unittest .mock import patch
1412
1513import pytest
1614
@@ -1139,8 +1137,18 @@ def test_parse_set_cookie_headers_uses_unquote_with_octal(
11391137@pytest .mark .parametrize (
11401138 ("header" , "expected_name" , "expected_coded" ),
11411139 [
1142- (r'name="\012newline\012"' , "name" , r'"\012newline\012"' ),
1143- (r'tab="\011separated\011values"' , "tab" , r'"\011separated\011values"' ),
1140+ pytest .param (
1141+ r'name="\012newline\012"' ,
1142+ "name" ,
1143+ r'"\012newline\012"' ,
1144+ id = "newline-octal-012" ,
1145+ ),
1146+ pytest .param (
1147+ r'tab="\011separated\011values"' ,
1148+ "tab" ,
1149+ r'"\011separated\011values"' ,
1150+ id = "tab-octal-011" ,
1151+ ),
11441152 ],
11451153)
11461154def test_parse_set_cookie_headers_ctl_chars_from_octal (
@@ -1164,27 +1172,43 @@ def test_parse_set_cookie_headers_ctl_chars_from_octal(
11641172 # We just ensure it doesn't crash and the coded_value is preserved.
11651173
11661174
1167- def test_parse_set_cookie_headers_literal_ctl_chars () -> None :
1175+ @pytest .mark .parametrize (
1176+ ("header" , "expected_name" ),
1177+ [
1178+ pytest .param (
1179+ 'name="a\x07 b"' ,
1180+ "name" ,
1181+ id = "bel-in-value" ,
1182+ ),
1183+ pytest .param (
1184+ 'bad="a\x07 b"; good=value' ,
1185+ "bad" ,
1186+ id = "bel-with-attribute" ,
1187+ ),
1188+ ],
1189+ )
1190+ def test_parse_set_cookie_headers_literal_ctl_chars (
1191+ header : str , expected_name : str
1192+ ) -> None :
11681193 r"""Ensure literal control characters in a cookie value don't crash the parser.
11691194
11701195 If the raw header itself contains a control character (e.g. BEL \\x07),
11711196 both the decoded value and coded_value are unsalvageable. The parser
11721197 should gracefully skip the cookie instead of raising CookieError.
11731198 """
1174- result = parse_set_cookie_headers (['name="a \x07 b"' ])
1199+ result = parse_set_cookie_headers ([header ])
11751200 # On CPython with CVE-2026-3644 patch the cookie is skipped;
11761201 # on older builds it may be accepted. Either way, no crash.
11771202 if result :
1178- assert result [0 ][0 ] == "name"
1203+ assert result [0 ][0 ] == expected_name
11791204
11801205
11811206def test_parse_set_cookie_headers_literal_ctl_chars_preserves_others () -> None :
11821207 """Ensure a cookie with literal control chars doesn't break subsequent cookies."""
11831208 result = parse_set_cookie_headers (['bad="a\x07 b"; good=value' , "another=cookie" ])
11841209 # "good" is an attribute of "bad" (same header), so it's not a separate cookie.
11851210 # "another" is in a separate header and must always be preserved.
1186- names = [name for name , _ in result ]
1187- assert "another" in names
1211+ assert any (name == "another" for name , _ in result )
11881212
11891213
11901214# Tests for parse_cookie_header (RFC 6265 compliant Cookie header parser)
@@ -1660,8 +1684,7 @@ def test_parse_cookie_header_literal_ctl_chars() -> None:
16601684 result = parse_cookie_header ('name="a\x07 b"; good=cookie' )
16611685 # On CPython with CVE-2026-3644 patch the bad cookie is skipped;
16621686 # on older builds it may be accepted. Either way, no crash.
1663- names = [name for name , _ in result ]
1664- assert "good" in names
1687+ assert any (name == "good" for name , _ in result )
16651688
16661689
16671690@pytest .mark .parametrize (
@@ -1855,23 +1878,24 @@ def test_unquote_compatibility_with_simplecookie(test_value: str) -> None:
18551878
18561879
18571880@pytest .fixture
1858- def mock_strict_morsel () -> typing .Iterator [None ]:
1881+ def mock_strict_morsel (
1882+ monkeypatch : pytest .MonkeyPatch ,
1883+ ) -> None :
18591884 original_setstate = Morsel .__setstate__ # type: ignore[attr-defined]
18601885
18611886 def _mock_setstate (self : Morsel [str ], state : dict [str , str ]) -> None :
18621887 if any (ord (c ) < 32 for c in state .get ("value" , "" )):
18631888 raise CookieError ()
18641889 original_setstate (self , state )
18651890
1866- with patch (
1891+ monkeypatch . setattr (
18671892 "aiohttp._cookie_helpers.Morsel.__setstate__" ,
1868- autospec = True ,
1869- side_effect = _mock_setstate ,
1870- ):
1871- yield
1893+ _mock_setstate ,
1894+ )
18721895
18731896
1874- def test_cookie_helpers_cve_fallback (mock_strict_morsel : None ) -> None :
1897+ @pytest .mark .usefixtures ("mock_strict_morsel" )
1898+ def test_cookie_helpers_cve_fallback () -> None :
18751899 m : Morsel [str ] = Morsel ()
18761900 assert helpers ._safe_set_morsel_state (m , "k" , "v\n " , "v\\ 012" ) is True
18771901 assert m .value == "v\\ 012"
0 commit comments