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

Conversation

AhmedNassar7
Copy link
Contributor

Trac ticket number

ticket-35673

Branch description

Problem:
Django's ExceptionReporter crashes with infinite loops when handling requests that exceed DATA_UPLOAD_MAX_NUMBER_FIELDS limits, resulting in blank 500 error pages instead of useful debug information.

Solution:
Implemented SafeExceptionRequest wrapper class that safely handles request.GET and request.FILES access by catching TooManyFieldsSent/TooManyFilesSent exceptions and returning empty collections with error indicators.

Checklist

  • This PR targets the main branch.
  • The commit message is written in past tense, mentions the ticket number, and ends with a period.
  • I have checked the "Has patch" ticket flag in the Trac system.
  • I have added or updated relevant tests.
  • I have added or updated relevant docs, including release notes if applicable.
  • I have attached screenshots in both light and dark modes for any UI changes.

Copy link
Contributor

@sarahboyce sarahboyce left a comment

Choose a reason for hiding this comment

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

Thank you, this is a great start ⭐

Comment on lines 442 to 451
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

Copy link
Contributor

@sarahboyce sarahboyce left a comment

Choose a reason for hiding this comment

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

Thank you for the updates 👍 this is getting closer ⭐

c["request_FILES_items"] = self.request.FILES.items()
try:
c["request_GET_items"] = self.request.GET.items()
c["request_GET_error"] = None
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
c["request_GET_error"] = None

We can omit this

Comment on lines +489 to +496
@override_settings(DATA_UPLOAD_MAX_NUMBER_FIELDS=1)
def test_max_number_of_fields_exceeded(self):
with self.assertLogs("django.request", "ERROR"):
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)
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
@override_settings(DATA_UPLOAD_MAX_NUMBER_FIELDS=1)
def test_max_number_of_fields_exceeded(self):
with self.assertLogs("django.request", "ERROR"):
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)
@override_settings(DATA_UPLOAD_MAX_NUMBER_FIELDS=1)
def test_max_number_of_fields_exceeded_get(self):
with self.assertLogs("django.request", "ERROR"):
response = self.client.get("/raises500/", {"a": "1", "b": "2"})
self.assertEqual(response.status_code, 500)
self.assertContains(
response,
"The number of GET/POST parameters exceeded "
"settings.DATA_UPLOAD_MAX_NUMBER_FIELDS.",
status_code=500
)
@override_settings(DATA_UPLOAD_MAX_NUMBER_FILES=1)
def test_max_number_of_fields_exceeded_files(self):
data = {
"file_data.txt": SimpleUploadedFile("file_data.txt", b"data"),
"file_data_2.txt": SimpleUploadedFile("file_data_2.txt", b"data2"),
}
with self.assertLogs("django.request", "ERROR"):
response = self.client.post("/raises/", data)
self.assertContains(
response,
"The number of files exceeded "
"settings.DATA_UPLOAD_MAX_NUMBER_FILES.",
status_code=500
)

You're missing a test for the files case
I have written an example test here but this currently fails because there is not error handling in accessing POST data:

  File "/path-to-django/django/views/debug.py", line 398, in get_traceback_data
    self.filter.get_post_parameters(self.request).items()
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/path-to-django/django/views/debug.py", line 225, in get_post_parameters
    return request.POST
           ^^^^^^^^^^^^

This needs similar error handling

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants