diff --git a/django/core/handlers/exception.py b/django/core/handlers/exception.py index f1c7b57891..48324372b4 100644 --- a/django/core/handlers/exception.py +++ b/django/core/handlers/exception.py @@ -7,7 +7,10 @@ from functools import wraps from django.conf import settings from django.core import signals -from django.core.exceptions import PermissionDenied, SuspiciousOperation +from django.core.exceptions import ( + PermissionDenied, RequestDataTooBig, SuspiciousOperation, + TooManyFieldsSent, +) from django.http import Http404 from django.http.multipartparser import MultiPartParserError from django.urls import get_resolver, get_urlconf @@ -64,6 +67,11 @@ def response_for_exception(request, exc): response = get_exception_response(request, get_resolver(get_urlconf()), 400, exc) elif isinstance(exc, SuspiciousOperation): + if isinstance(exc, (RequestDataTooBig, TooManyFieldsSent)): + # POST data can't be accessed again, otherwise the original + # exception would be raised. + request._mark_post_parse_error() + # The request logger receives events for any problematic request # The security logger receives events for all SuspiciousOperations security_logger = logging.getLogger('django.security.%s' % exc.__class__.__name__) diff --git a/docs/releases/1.10.6.txt b/docs/releases/1.10.6.txt index dc5c49938f..483854c0e6 100644 --- a/docs/releases/1.10.6.txt +++ b/docs/releases/1.10.6.txt @@ -11,3 +11,6 @@ Bugfixes * Fixed ``ClearableFileInput``’s "Clear" checkbox on model form fields where the model field has a ``default`` (:ticket:`27805`). + +* Fixed ``RequestDataTooBig`` and ``TooManyFieldsSent`` exceptions crashing + rather than generating a bad request response (:ticket:`27820`). diff --git a/tests/handlers/test_exception.py b/tests/handlers/test_exception.py new file mode 100644 index 0000000000..7afd4acc6b --- /dev/null +++ b/tests/handlers/test_exception.py @@ -0,0 +1,27 @@ +from django.core.handlers.wsgi import WSGIHandler +from django.test import SimpleTestCase, override_settings +from django.test.client import FakePayload + + +class ExceptionHandlerTests(SimpleTestCase): + + def get_suspicious_environ(self): + payload = FakePayload('a=1&a=2;a=3\r\n') + return { + 'REQUEST_METHOD': 'POST', + 'CONTENT_TYPE': 'application/x-www-form-urlencoded', + 'CONTENT_LENGTH': len(payload), + 'wsgi.input': payload, + 'SERVER_NAME': 'test', + 'SERVER_PORT': '8000', + } + + @override_settings(DATA_UPLOAD_MAX_MEMORY_SIZE=12) + def test_data_upload_max_memory_size_exceeded(self): + response = WSGIHandler()(self.get_suspicious_environ(), lambda *a, **k: None) + self.assertEqual(response.status_code, 400) + + @override_settings(DATA_UPLOAD_MAX_NUMBER_FIELDS=2) + def test_data_upload_max_number_fields_exceeded(self): + response = WSGIHandler()(self.get_suspicious_environ(), lambda *a, **k: None) + self.assertEqual(response.status_code, 400)