diff --git a/rest_framework/utils/encoders.py b/rest_framework/utils/encoders.py index a7875a868..20bb1482a 100644 --- a/rest_framework/utils/encoders.py +++ b/rest_framework/utils/encoders.py @@ -19,6 +19,11 @@ class JSONEncoder(json.JSONEncoder): JSONEncoder subclass that knows how to encode date/time/timedelta, decimal types, generators and other basic python objects. """ + + enforce_rfc7159_numbers = True + rfc7159_min_number = -(2**53) + 1 + rfc7159_max_number = (2**53) - 1 + def default(self, obj): # For Date Time string spec, see ECMA 262 # https://ecma-international.org/ecma-262/5.1/#sec-15.9.1.15 @@ -63,4 +68,17 @@ class JSONEncoder(json.JSONEncoder): pass elif hasattr(obj, '__iter__'): return tuple(item for item in obj) + elif isinstance(obj, int): + # If RFC-7159 is enforced, numbers must not be outside its range + if self.enforce_rfc7159_numbers and not ( + self.rfc7159_min_number <= obj <= self.rfc7159_max_number + ): + raise ValueError( + "Cannot render number {} as integer if RFC 7159 is enforced. " + "Value must be between {} and {}".format( + obj, self.rfc7159_min_number, self.rfc7159_max_number + ) + ) + else: + return obj return super().default(obj) diff --git a/tests/test_encoders.py b/tests/test_encoders.py index c66954b80..9c1a52c00 100644 --- a/tests/test_encoders.py +++ b/tests/test_encoders.py @@ -93,3 +93,17 @@ class JSONEncoderTests(TestCase): """ foo = MockList() assert self.encoder.default(foo) == [1, 2, 3] + + def test_encode_int_outside_rfc7159_range(self): + # Values lower than minimum allowed must fail + with pytest.raises(ValueError): + self.encoder.default(self.encoder.rfc7159_min_number - 1) + + # Values greater than maximum allowed must fail + with pytest.raises(ValueError): + self.encoder.default(self.encoder.rfc7159_max_number + 1) + + # Values within RFC 7159 range are allowed + self.encoder.default(self.encoder.rfc7159_min_number) == self.encoder.rfc7159_min_number + self.encoder.default(self.encoder.rfc7159_max_number) == self.encoder.rfc7159_max_number + self.encoder.default(42) == 42