mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-02-03 05:04:31 +03:00
Add 'STRICT_JSON' API setting.
STRICT_JSON controls the renderer & parser behavior on whether or not to accept non-standard float values (NaN, Infinity).
This commit is contained in:
parent
d740bae95a
commit
8ab75a2f01
|
@ -22,6 +22,7 @@ from django.utils.six.moves.urllib import parse as urlparse
|
|||
|
||||
from rest_framework import renderers
|
||||
from rest_framework.exceptions import ParseError
|
||||
from rest_framework.settings import api_settings
|
||||
from rest_framework.utils import json
|
||||
|
||||
|
||||
|
@ -53,6 +54,7 @@ class JSONParser(BaseParser):
|
|||
"""
|
||||
media_type = 'application/json'
|
||||
renderer_class = renderers.JSONRenderer
|
||||
strict = api_settings.STRICT_JSON
|
||||
|
||||
def parse(self, stream, media_type=None, parser_context=None):
|
||||
"""
|
||||
|
@ -63,7 +65,8 @@ class JSONParser(BaseParser):
|
|||
|
||||
try:
|
||||
decoded_stream = codecs.getreader(encoding)(stream)
|
||||
return json.load(decoded_stream)
|
||||
parse_constant = json.strict_constant if self.strict else None
|
||||
return json.load(decoded_stream, parse_constant=parse_constant)
|
||||
except ValueError as exc:
|
||||
raise ParseError('JSON parse error - %s' % six.text_type(exc))
|
||||
|
||||
|
|
|
@ -61,6 +61,7 @@ class JSONRenderer(BaseRenderer):
|
|||
encoder_class = encoders.JSONEncoder
|
||||
ensure_ascii = not api_settings.UNICODE_JSON
|
||||
compact = api_settings.COMPACT_JSON
|
||||
strict = api_settings.STRICT_JSON
|
||||
|
||||
# We don't set a charset because JSON is a binary encoding,
|
||||
# that can be encoded as utf-8, utf-16 or utf-32.
|
||||
|
@ -101,7 +102,7 @@ class JSONRenderer(BaseRenderer):
|
|||
ret = json.dumps(
|
||||
data, cls=self.encoder_class,
|
||||
indent=indent, ensure_ascii=self.ensure_ascii,
|
||||
separators=separators
|
||||
allow_nan=not self.strict, separators=separators
|
||||
)
|
||||
|
||||
# On python 2.x json.dumps() returns bytestrings if ensure_ascii=True,
|
||||
|
|
|
@ -110,6 +110,7 @@ DEFAULTS = {
|
|||
# Encoding
|
||||
'UNICODE_JSON': True,
|
||||
'COMPACT_JSON': True,
|
||||
'STRICT_JSON': True,
|
||||
'COERCE_DECIMAL_TO_STRING': True,
|
||||
'UPLOADED_FILES_USE_URL': True,
|
||||
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import math
|
||||
|
||||
import pytest
|
||||
from django import forms
|
||||
from django.core.files.uploadhandler import (
|
||||
|
@ -9,7 +10,7 @@ from django.core.files.uploadhandler import (
|
|||
)
|
||||
from django.http.request import RawPostDataException
|
||||
from django.test import TestCase
|
||||
from django.utils.six.moves import StringIO
|
||||
from django.utils.six import BytesIO, StringIO
|
||||
|
||||
from rest_framework.exceptions import ParseError
|
||||
from rest_framework.parsers import (
|
||||
|
@ -42,7 +43,6 @@ class TestFileUploadParser(TestCase):
|
|||
def setUp(self):
|
||||
class MockRequest(object):
|
||||
pass
|
||||
from io import BytesIO
|
||||
self.stream = BytesIO(
|
||||
"Test text file".encode('utf-8')
|
||||
)
|
||||
|
@ -129,6 +129,24 @@ class TestFileUploadParser(TestCase):
|
|||
self.parser_context['request'].META['HTTP_CONTENT_DISPOSITION'] = disposition
|
||||
|
||||
|
||||
class TestJSONParser(TestCase):
|
||||
def bytes(self, value):
|
||||
return BytesIO(value.encode('utf-8'))
|
||||
|
||||
def test_float_strictness(self):
|
||||
parser = JSONParser()
|
||||
|
||||
# Default to strict
|
||||
for value in ['Infinity', '-Infinity', 'NaN']:
|
||||
with pytest.raises(ParseError):
|
||||
parser.parse(self.bytes(value))
|
||||
|
||||
parser.strict = False
|
||||
assert parser.parse(self.bytes('Infinity')) == float('inf')
|
||||
assert parser.parse(self.bytes('-Infinity')) == float('-inf')
|
||||
assert math.isnan(parser.parse(self.bytes('NaN')))
|
||||
|
||||
|
||||
class TestPOSTAccessed(TestCase):
|
||||
def setUp(self):
|
||||
self.factory = APIRequestFactory()
|
||||
|
|
|
@ -358,6 +358,19 @@ class JSONRendererTests(TestCase):
|
|||
with self.assertRaises(TypeError):
|
||||
JSONRenderer().render(x)
|
||||
|
||||
def test_float_strictness(self):
|
||||
renderer = JSONRenderer()
|
||||
|
||||
# Default to strict
|
||||
for value in [float('inf'), float('-inf'), float('nan')]:
|
||||
with pytest.raises(ValueError):
|
||||
renderer.render(value)
|
||||
|
||||
renderer.strict = False
|
||||
assert renderer.render(float('inf')) == b'Infinity'
|
||||
assert renderer.render(float('-inf')) == b'-Infinity'
|
||||
assert renderer.render(float('nan')) == b'NaN'
|
||||
|
||||
def test_without_content_type_args(self):
|
||||
"""
|
||||
Test basic JSON rendering.
|
||||
|
|
|
@ -198,3 +198,10 @@ class JsonFloatTests(TestCase):
|
|||
|
||||
with self.assertRaises(ValueError):
|
||||
json.loads("NaN")
|
||||
|
||||
|
||||
@override_settings(STRICT_JSON=False)
|
||||
class NonStrictJsonFloatTests(JsonFloatTests):
|
||||
"""
|
||||
'STRICT_JSON = False' should not somehow affect internal json behavior
|
||||
"""
|
||||
|
|
Loading…
Reference in New Issue
Block a user