diff --git a/playwright/_impl/_fetch.py b/playwright/_impl/_fetch.py index 6181f22b2..e8b812b92 100644 --- a/playwright/_impl/_fetch.py +++ b/playwright/_impl/_fetch.py @@ -395,7 +395,11 @@ async def _inner_fetch( elif isinstance(data, bytes): post_data_buffer = data elif isinstance(data, (dict, list, int, bool)): - json_data = json.dumps(data) + try: + # NaN and Infinity are not valid JSON. + json_data = json.dumps(data, allow_nan=False) + except ValueError as e: + raise Error(str(e)) from None else: raise Error(f"Unsupported 'data' type: {type(data)}") elif form: diff --git a/tests/async/test_fetch_global.py b/tests/async/test_fetch_global.py index 10f82583c..e09567f71 100644 --- a/tests/async/test_fetch_global.py +++ b/tests/async/test_fetch_global.py @@ -474,6 +474,16 @@ async def test_should_serialize_request_data( await request.dispose() +@pytest.mark.parametrize("value", [float("inf"), float("-inf"), float("nan")]) +async def test_should_reject_non_finite_floats_in_request_data( + playwright: Playwright, server: Server, value: float +) -> None: + request = await playwright.request.new_context() + with pytest.raises(Error, match="Out of range float values are not JSON"): + await request.post(server.EMPTY_PAGE, data={"value": value}) + await request.dispose() + + async def test_should_retry_ECONNRESET(playwright: Playwright, server: Server) -> None: request_count = 0 diff --git a/tests/sync/test_fetch_global.py b/tests/sync/test_fetch_global.py index 15a11fca8..ffc91be60 100644 --- a/tests/sync/test_fetch_global.py +++ b/tests/sync/test_fetch_global.py @@ -334,6 +334,16 @@ def test_should_serialize_null_values_in_json( request.dispose() +@pytest.mark.parametrize("value", [float("inf"), float("-inf"), float("nan")]) +def test_should_reject_non_finite_floats_in_request_data( + playwright: Playwright, server: Server, value: float +) -> None: + request = playwright.request.new_context() + with pytest.raises(Error, match="Out of range float values are not JSON"): + request.post(server.EMPTY_PAGE, data={"value": value}) + request.dispose() + + def test_should_throw_when_fail_on_status_code_is_true( playwright: Playwright, server: Server ) -> None: