diff --git a/tests/test_benchmarks_cookie_helpers.py b/tests/test_benchmarks_cookie_helpers.py new file mode 100644 index 00000000000..5a06a2d6b50 --- /dev/null +++ b/tests/test_benchmarks_cookie_helpers.py @@ -0,0 +1,28 @@ +"""codspeed benchmarks for cookie helpers.""" + +from typing import TYPE_CHECKING + +import pytest + +from aiohttp._cookie_helpers import _COOKIE_PATTERN + +if TYPE_CHECKING: + from pytest_codspeed import BenchmarkFixture +else: + pytest_codspeed = pytest.importorskip("pytest_codspeed") + BenchmarkFixture = pytest_codspeed.BenchmarkFixture + + +def test_cookie_pattern_redos_payload(benchmark: BenchmarkFixture) -> None: + """Benchmark ``_COOKIE_PATTERN`` against a ReDoS payload. + + A regression that reintroduces catastrophic backtracking shows up here as + a large, deterministic slowdown instead of a flaky wall-clock assertion. + """ + value = "a" + "=" * 21651 + "\x00" + # This payload must not match. + assert _COOKIE_PATTERN.match(value) is None + + @benchmark + def _run() -> None: + _COOKIE_PATTERN.match(value) diff --git a/tests/test_cookie_helpers.py b/tests/test_cookie_helpers.py index be6228d698f..91ed63c51bb 100644 --- a/tests/test_cookie_helpers.py +++ b/tests/test_cookie_helpers.py @@ -2,7 +2,6 @@ import logging import sys -import time from http.cookies import ( CookieError, Morsel, @@ -637,23 +636,6 @@ def test_cookie_pattern_matches_partitioned_attribute(test_string: str) -> None: assert match.group("key").lower() == "partitioned" -def test_cookie_pattern_performance() -> None: - """Test that the cookie pattern doesn't suffer from ReDoS issues.""" - COOKIE_PATTERN_TIME_THRESHOLD_SECONDS = 0.08 - value = "a" + "=" * 21651 + "\x00" - start = time.perf_counter() - match = helpers._COOKIE_PATTERN.match(value) - elapsed = time.perf_counter() - start - - # If this is taking more time, there's probably a performance/ReDoS issue. - assert elapsed < COOKIE_PATTERN_TIME_THRESHOLD_SECONDS, ( - f"Pattern took {elapsed * 1000:.1f}ms, " - f"expected <{COOKIE_PATTERN_TIME_THRESHOLD_SECONDS * 1000:.0f}ms - potential ReDoS issue" - ) - # This example shouldn't produce a match either. - assert match is None - - def test_parse_set_cookie_headers_issue_7993_double_quotes() -> None: """ Test that cookies with unmatched opening quotes don't break parsing of subsequent cookies.