Skip to content

Fixed #35673 -- Enhanced ExceptionReporter to handle GET and FILES parameters #19702

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Enhanced ExceptionReporter to gracefully handle too many GET and FILE…
…S parameters
  • Loading branch information
AhmedNassar7 committed Aug 4, 2025
commit 7a95e8bbe9d76e24c4d36f07398136c68f291cd9
46 changes: 43 additions & 3 deletions django/views/debug.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from pathlib import Path

from django.conf import settings
from django.core.exceptions import TooManyFieldsSent, TooManyFilesSent
from django.http import Http404, HttpResponse, HttpResponseNotFound
from django.template import Context, Engine, TemplateDoesNotExist
from django.template.defaultfilters import pprint
Expand Down Expand Up @@ -309,6 +310,27 @@ def get_traceback_frame_variables(self, request, tb_frame):
return cleansed.items()


class SafeExceptionRequest:
def __init__(self, request):
self._request = request

def __getattr__(self, name):
if name in ("GET", "FILES"):
try:
return getattr(self._request, name)
except (TooManyFieldsSent, TooManyFilesSent):
from django.http import QueryDict

return QueryDict()
return getattr(self._request, name)

def __str__(self):
return str(self._request)

def __repr__(self):
return repr(self._request)


class ExceptionReporter:
"""Organize and coordinate reporting on exceptions."""

Expand Down Expand Up @@ -389,7 +411,7 @@ def get_traceback_data(self):
"is_email": self.is_email,
"unicode_hint": unicode_hint,
"frames": frames,
"request": self.request,
"request": SafeExceptionRequest(self.request) if self.request else None,
"request_meta": self.filter.get_safe_request_meta(self.request),
"request_COOKIES_items": self.filter.get_safe_cookies(self.request).items(),
"user_str": user_str,
Expand All @@ -407,8 +429,26 @@ def get_traceback_data(self):
"postmortem": self.postmortem,
}
if self.request is not None:
c["request_GET_items"] = self.request.GET.items()
c["request_FILES_items"] = self.request.FILES.items()
try:
c["request_GET_items"] = self.request.GET.items()
except TooManyFieldsSent:
c["request_GET_items"] = [
(
"<could not parse>",
"Number of GET paramters exceeded "
"DATA_UPLOAD_MAX_NUMBER_FIELDS.",
)
]
try:
c["request_FILES_items"] = self.request.FILES.items()
except TooManyFilesSent:
c["request_FILES_items"] = [
(
"<could not parse>",
"Number of FILES parameters exceeded "
"DATA_UPLOAD_MAX_NUMBER_FILES",
)
]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
try:
c["request_FILES_items"] = self.request.FILES.items()
except TooManyFilesSent:
c["request_FILES_items"] = [
(
"<could not parse>",
"Number of FILES parameters exceeded "
"DATA_UPLOAD_MAX_NUMBER_FILES",
)
]
c["request_FILES_items"] = self.request.FILES.items()

Note that this can be reverted without any test failures
We might also want to test for (and possibly handle) too many POST parameters

c["request_insecure_uri"] = self._get_raw_insecure_uri()
c["raising_view_name"] = get_caller(self.request)

Expand Down
8 changes: 8 additions & 0 deletions tests/view_tests/tests/test_debug.py
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,14 @@ def test_template_override_exception_reporter(self):
response = self.client.get("/raises500/", headers={"accept": "text/plain"})
self.assertContains(response, "Oh dear, an error occurred!", status_code=500)

@override_settings(DATA_UPLOAD_MAX_NUMBER_FIELDS=1)
def test_max_number_of_fields_exceeded(self):
response = self.client.get("/raises500/", {"a": "1", "b": "2"})

self.assertEqual(response.status_code, 500)
self.assertContains(response, '<div class="context" id="', status_code=500)
self.assertContains(response, "Exception", status_code=500)


class DebugViewQueriesAllowedTests(SimpleTestCase):
# May need a query to initialize MySQL connection
Expand Down
3 changes: 2 additions & 1 deletion tests/view_tests/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

def index_page(request):
"""Dummy index page"""
request.GET.getlist("a")
return HttpResponse("<html><body>Dummy page</body></html>")


Expand All @@ -45,7 +46,7 @@ def raises500(request):
# We need to inspect the HTML generated by the fancy 500 debug view but
# the test client ignores it, so we send it explicitly.
try:
raise Exception
raise Exception("Test exception to trigger debug view")
except Exception:
return technical_500_response(request, *sys.exc_info())

Expand Down
Loading