diff --git a/CHANGES/4214.bugfix b/CHANGES/4214.bugfix new file mode 100644 index 00000000000..57b35c9c4a5 --- /dev/null +++ b/CHANGES/4214.bugfix @@ -0,0 +1 @@ +Raising RuntimeError when trying to get encoding from not read body diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index b042eeb3020..20fc287d325 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -268,6 +268,7 @@ Vladimir Kozlovski Vladimir Rutsky Vladimir Shulyak Vladimir Zakharov +Vladyslav Bohaichuk Vladyslav Bondar W. Trevor King Wei Lin diff --git a/aiohttp/client_reqrep.py b/aiohttp/client_reqrep.py index bf6762ad3c9..70bf1bde6ba 100644 --- a/aiohttp/client_reqrep.py +++ b/aiohttp/client_reqrep.py @@ -938,6 +938,9 @@ def get_encoding(self) -> str: if mimetype.type == 'application' and mimetype.subtype == 'json': # RFC 7159 states that the default encoding is UTF-8. encoding = 'utf-8' + elif self._body is None: + raise RuntimeError('Cannot guess the encoding of ' + 'a not yet read body') else: encoding = chardet.detect(self._body)['encoding'] if not encoding: diff --git a/docs/client_reference.rst b/docs/client_reference.rst index 27aef1df7f6..4fefc76c5c0 100644 --- a/docs/client_reference.rst +++ b/docs/client_reference.rst @@ -1305,6 +1305,9 @@ Response object decode a response. Some encodings detected by cchardet are not known by Python (e.g. VISCII). + :raise RuntimeError: if called before the body has been read, + for :term:`cchardet` usage + .. versionadded:: 3.0 diff --git a/tests/test_client_response.py b/tests/test_client_response.py index 089b6f0bf7a..0c795820301 100644 --- a/tests/test_client_response.py +++ b/tests/test_client_response.py @@ -424,6 +424,33 @@ def side_effect(*args, **kwargs): assert response.get_encoding().lower() in ('windows-1251', 'maccyrillic') +async def test_get_encoding_body_none(loop, session) -> None: + response = ClientResponse('get', URL('http://def-cl-resp.org'), + request_info=mock.Mock(), + writer=mock.Mock(), + continue100=None, + timer=TimerNoop(), + traces=[], + loop=loop, + session=session) + + def side_effect(*args, **kwargs): + fut = loop.create_future() + fut.set_result('{"encoding": "test"}') + return fut + + response._headers = {'Content-Type': 'text/html'} + content = response.content = mock.Mock() + content.read.side_effect = side_effect + + with pytest.raises( + RuntimeError, + match='^Cannot guess the encoding of a not yet read body$', + ): + response.get_encoding() + assert response.closed + + async def test_text_after_read(loop, session) -> None: response = ClientResponse('get', URL('http://def-cl-resp.org'), request_info=mock.Mock(),