mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-08-04 20:40:14 +03:00
raise possible problem and a possible (but probably not the correct) solution.
This commit is contained in:
parent
411511622d
commit
7ff5e79e83
|
@ -814,6 +814,7 @@ class IntegerField(WritableField):
|
|||
type_label = 'integer'
|
||||
form_field_class = forms.IntegerField
|
||||
empty = 0
|
||||
max_digits = 39 # len(str(2**128))
|
||||
|
||||
default_error_messages = {
|
||||
'invalid': _('Enter a whole number.'),
|
||||
|
@ -835,7 +836,9 @@ class IntegerField(WritableField):
|
|||
return None
|
||||
|
||||
try:
|
||||
value = int(str(value))
|
||||
str_value = str(value)
|
||||
validators.MaxLengthValidator(self.max_digits)(str_value)
|
||||
value = int(str_value)
|
||||
except (ValueError, TypeError):
|
||||
raise ValidationError(self.error_messages['invalid'])
|
||||
return value
|
||||
|
@ -846,6 +849,7 @@ class FloatField(WritableField):
|
|||
type_label = 'float'
|
||||
form_field_class = forms.FloatField
|
||||
empty = 0
|
||||
max_digits = 17 # IEEE-754 double can get at most 17 significant digits.
|
||||
|
||||
default_error_messages = {
|
||||
'invalid': _("'%s' value must be a float."),
|
||||
|
@ -856,6 +860,7 @@ class FloatField(WritableField):
|
|||
return None
|
||||
|
||||
try:
|
||||
validators.MaxLengthValidator(self.max_digits)(str(value))
|
||||
return float(value)
|
||||
except (TypeError, ValueError):
|
||||
msg = self.error_messages['invalid'] % value
|
||||
|
@ -898,6 +903,9 @@ class DecimalField(WritableField):
|
|||
return None
|
||||
value = smart_text(value).strip()
|
||||
try:
|
||||
# to not change behavior something similar to
|
||||
# .validate(self, value) should be run
|
||||
# validators.MaxLengthValidator(self.max_digits)(str(value))
|
||||
value = Decimal(value)
|
||||
except DecimalException:
|
||||
raise ValidationError(self.error_messages['invalid'])
|
||||
|
|
|
@ -965,6 +965,53 @@ class FieldCallableDefault(TestCase):
|
|||
self.assertEqual(into, {'field': 'foo bar'})
|
||||
|
||||
|
||||
class CanHangOnHugeNumbers(TestCase):
|
||||
"""
|
||||
Test that number fields will not hang on a very large input. The
|
||||
test and one approach to handling it is not intended as a final solution
|
||||
but a starting point for a discussion.
|
||||
|
||||
The main concern is when using a serializer in the context of the rest
|
||||
framework. A malicious user could send a large number as a string
|
||||
representation (here we use a small example, str(2**256), that is big
|
||||
enough for demonstration). Since the number is converted to an integer
|
||||
in fields.IntegerField.from_native function without checking the length
|
||||
of the input, the system can hang. One solution is to use a length
|
||||
validation before converting, however this seems a little messy.
|
||||
Similar concerns exist in FloatField and DecimalField where a similar
|
||||
solution could be used be used.
|
||||
"""
|
||||
def test_huge_numbers_do_not_cause_a_hang(self):
|
||||
|
||||
class NumberModel(models.Model):
|
||||
integer = models.IntegerField(
|
||||
validators=[validators.MaxValueValidator(2 ** 32)])
|
||||
decimal = models.DecimalField(max_digits=17)
|
||||
double = models.FloatField()
|
||||
|
||||
class NumberSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = NumberModel
|
||||
|
||||
number = NumberModel(integer=1, decimal=3.14, double=2.7182818284)
|
||||
|
||||
serializer = NumberSerializer(
|
||||
number, data={"integer": 2, "decimal": 3.0, "double": 2.7})
|
||||
self.assertTrue(serializer.is_valid())
|
||||
|
||||
serializer = NumberSerializer(
|
||||
number, data={"integer": str(2 ** 256)}, partial=True)
|
||||
self.assertFalse(serializer.is_valid())
|
||||
|
||||
serializer = NumberSerializer(
|
||||
number, data={"decimal": '3.14159265358979323846264'}, partial=True)
|
||||
self.assertFalse(serializer.is_valid())
|
||||
|
||||
serializer = NumberSerializer(
|
||||
number, data={"double": '2.718281828459045235360287'}, partial=True)
|
||||
self.assertFalse(serializer.is_valid())
|
||||
|
||||
|
||||
class CustomIntegerField(TestCase):
|
||||
"""
|
||||
Test that custom fields apply min_value and max_value constraints
|
||||
|
|
Loading…
Reference in New Issue
Block a user