diff --git a/aiohttp/client_reqrep.py b/aiohttp/client_reqrep.py index 22f0e077f64..25160f198bc 100644 --- a/aiohttp/client_reqrep.py +++ b/aiohttp/client_reqrep.py @@ -78,6 +78,7 @@ _CONNECTION_CLOSED_EXCEPTION = ClientConnectionError("Connection closed") _CONTAINS_CONTROL_CHAR_RE = re.compile(r"[^-!#$%&'*+.^_`|~0-9a-zA-Z]") +_DIGITS_RE = re.compile(r"\d+", re.ASCII) def _gen_default_accept_encoding() -> str: @@ -753,12 +754,9 @@ def _get_content_length(self) -> int | None: return None content_length_hdr = self.headers[hdrs.CONTENT_LENGTH] - try: - return int(content_length_hdr) - except ValueError: - raise ValueError( - f"Invalid Content-Length header: {content_length_hdr}" - ) from None + if not _DIGITS_RE.fullmatch(content_length_hdr): + raise ValueError(f"Invalid Content-Length header: {content_length_hdr!r}") + return int(content_length_hdr) @property def _writer(self) -> asyncio.Task[None] | None: diff --git a/tests/test_client_request.py b/tests/test_client_request.py index 751deaa8f18..6cd617a1674 100644 --- a/tests/test_client_request.py +++ b/tests/test_client_request.py @@ -1822,7 +1822,24 @@ async def test_get_content_length(make_client_request: _RequestMaker) -> None: # Invalid Content-Length header req.headers["Content-Length"] = "invalid" - with pytest.raises(ValueError, match="Invalid Content-Length header: invalid"): + with pytest.raises(ValueError, match="Invalid Content-Length header"): + req._get_content_length() + + +async def test_get_content_length_invalid_formats( + make_client_request: _RequestMaker, +) -> None: + req = make_client_request("get", URL("http://python.org/")) + + req.headers["Content-Length"] = "100" + assert req._get_content_length() == 100 + + req.headers["Content-Length"] = "-100" + with pytest.raises(ValueError, match="Invalid Content-Length header"): + req._get_content_length() + + req.headers["Content-Length"] = "рел" # Devengali number 5 + with pytest.raises(ValueError, match="Invalid Content-Length header"): req._get_content_length()