fix content length mismatch in windows and other platform

The current implementation of `sanic` attempts to make use of `ujson` if
it's available in the system and if not, it will default to the inbuilt
`json` module provided by python.

The current implementation of `ujson` does not provide a mechanism to
provide a custom `seperators` parameter as part of the `dumps` method
invocation and the default behavior of the module is to strip all the
spaces around seperators such as `:` and `,`. This leads to an
inconsistency in the response length when the response is generated
using the `ujson` and in built `json` module provided by python.

To maintain the consistency, this commit overrides the default behavior
of the `dumps` method provided by the `json` module to add a `seperators`
argument that will strip the white spaces around these character like
the default behavior of `ujson`

This addresses the issue referenced in #1398

Signed-off-by: Harsha Narayana <harsha2k4@gmail.com>
This commit is contained in:
Harsha Narayana 2018-11-07 21:32:34 +05:30
parent 92b73a6f4f
commit d4d1df03c9
No known key found for this signature in database
GPG Key ID: 8AF211CB60D4B28C
2 changed files with 12 additions and 13 deletions

View File

@ -1,3 +1,4 @@
from functools import partial
from mimetypes import guess_type
from os import path
from urllib.parse import quote_plus
@ -12,7 +13,11 @@ from sanic.helpers import STATUS_CODES, has_message_body, remove_entity_headers
try:
from ujson import dumps as json_dumps
except BaseException:
from json import dumps as json_dumps
from json import dumps
# This is done in order to ensure that the JSON response is
# kept consistent across both ujson and inbuilt json usage.
json_dumps = partial(dumps, separators=(",", ":"))
class BaseHTTPResponse:

View File

@ -1,20 +1,19 @@
import sys
import asyncio
import inspect
import os
from aiofiles import os as async_os
from mimetypes import guess_type
from random import choice
from unittest.mock import MagicMock
from urllib.parse import unquote
import pytest
from random import choice
from aiofiles import os as async_os
from sanic.response import (
HTTPResponse, stream, StreamingHTTPResponse, file, file_stream, json
)
from sanic.server import HttpProtocol
from sanic.testing import HOST, PORT
from unittest.mock import MagicMock
JSON_DATA = {'ok': True}
@ -38,7 +37,6 @@ async def sample_streaming_fn(response):
def test_method_not_allowed(app):
@app.get('/')
async def test_get(request):
return response.json({'hello': 'world'})
@ -55,12 +53,12 @@ def test_method_not_allowed(app):
request, response = app.test_client.head('/')
assert response.status == 405
assert set(response.headers['Allow'].split(', ')) == set(['GET', 'POST'])
assert set(response.headers['Allow'].split(', ')) == {'GET', 'POST'}
assert response.headers['Content-Length'] == '0'
request, response = app.test_client.patch('/')
assert response.status == 405
assert set(response.headers['Allow'].split(', ')) == set(['GET', 'POST'])
assert set(response.headers['Allow'].split(', ')) == {'GET', 'POST'}
assert response.headers['Content-Length'] == '0'
@ -74,15 +72,11 @@ def test_response_header(app):
'CONTENT-TYPE': 'application/json'
})
is_windows = sys.platform in ['win32', 'cygwin']
request, response = app.test_client.get('/')
assert dict(response.headers) == {
'Connection': 'keep-alive',
'Keep-Alive': str(app.config.KEEP_ALIVE_TIMEOUT),
# response body contains an extra \r at the end if its windows
# TODO: this is the only place this difference shows up in our tests
# we should figure out a way to unify testing on both platforms
'Content-Length': '12' if is_windows else '11',
'Content-Length': '11',
'Content-Type': 'application/json',
}