Skip to content

Commit

Permalink
Fixed JSON response character set detection.
Browse files Browse the repository at this point in the history
RFC 7519 states that JSON *MUST* be encoded in UTF and that
the default encoding, in absence of charset in CONTENT_TYPE header is UTF-8.

This vastly improves performce when doing many small requests in environments
where the server does not specify the character by omitting chardet.
  • Loading branch information
Kimmo Parviainen-Jalanko committed Oct 27, 2016
1 parent e53af22 commit 80831fc
Show file tree
Hide file tree
Showing 3 changed files with 7 additions and 21 deletions.
1 change: 1 addition & 0 deletions CONTRIBUTORS.txt
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ Julien Duponchelle
Junjie Tao
Justas Trimailovas
Kay Zheng
Kimmo Parviainen-Jalanko
Kirill Klenov
Kirill Malovitsa
Kyrylo Perevozchikov
Expand Down
6 changes: 5 additions & 1 deletion aiohttp/client_reqrep.py
Original file line number Diff line number Diff line change
Expand Up @@ -728,7 +728,11 @@ def _get_encoding(self):

encoding = params.get('charset')
if not encoding:
encoding = chardet.detect(self._content)['encoding']
if mtype == 'application' and stype == 'json':
# RFC 7159 states that the default encoding is UTF-8.
encoding = 'utf-8'
else:
encoding = chardet.detect(self._content)['encoding']
if not encoding:
encoding = 'utf-8'

Expand Down
21 changes: 1 addition & 20 deletions tests/test_client_response.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ def side_effect(*args, **kwargs):
fut.set_result('{"тест": "пройден"}'.encode('cp1251'))
return fut

response.headers = {'Content-Type': 'application/json'}
response.headers = {'Content-Type': 'text/plain'}
content = response.content = mock.Mock()
content.read.side_effect = side_effect

Expand Down Expand Up @@ -275,25 +275,6 @@ def side_effect(*args, **kwargs):
assert not response._get_encoding.called


@asyncio.coroutine
def test_json_detect_encoding(loop):
response = ClientResponse('get', URL('http://def-cl-resp.org'))
response._post_init(loop)

def side_effect(*args, **kwargs):
fut = helpers.create_future(loop)
fut.set_result('{"тест": "пройден"}'.encode('cp1251'))
return fut

response.headers = {'Content-Type': 'application/json'}
content = response.content = mock.Mock()
content.read.side_effect = side_effect

res = yield from response.json()
assert res == {'тест': 'пройден'}
assert response._connection is None


def test_override_flow_control(loop):
class MyResponse(ClientResponse):
flow_control_class = aiohttp.StreamReader
Expand Down

0 comments on commit 80831fc

Please sign in to comment.