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 ⭐

@@ -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"})
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
response = self.client.get("/raises500/", {"a": "1", "b": "2"})
with self.assertLogs("django.request", "ERROR"):
response = self.client.get("/raises500/", {"a": "1", "b": "2"})

We want to capture the logging so we don't get noise when running the test

@@ -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,
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
"request": SafeExceptionRequest(self.request) if self.request else None,
"request": self.request,

We can revert this and remove the SafeExceptionRequest and instead do:

--- a/django/views/templates/technical_500.html
+++ b/django/views/templates/technical_500.html
@@ -354,7 +354,7 @@ Exception Value: {{ exception_value|force_escape }}{% if exception_notes %}{{ ex
   {% endif %}
 
   <h3 id="get-info">GET</h3>
-  {% if request.GET %}
+  {% if request_GET_items %}
     <table class="req">
       <thead>
         <tr>
@@ -398,7 +398,7 @@ Exception Value: {{ exception_value|force_escape }}{% if exception_notes %}{{ ex
   {% endif %}
 
   <h3 id="files-info">FILES</h3>
-  {% if request.FILES %}
+  {% if request_FILES_items %}
     <table class="req">
       <thead>
         <tr>

Copy link
Contributor

Choose a reason for hiding this comment

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

I also think in the template we should consider rendering the error differently rather than have it within a table with "Variable", "Value" headers, something like:

   <h3 id="files-info">FILES</h3>
-  {% if request.FILES %}
+  {% if request_FILES_items %}
     <table class="req">
       <thead>
         <tr>
@@ -415,6 +415,8 @@ Exception Value: {{ exception_value|force_escape }}{% if exception_notes %}{{ ex
   <h3 id="files-info">FILES</h3>
-  {% if request.FILES %}
+  {% if request_FILES_items %}
     <table class="req">
       <thead>
         <tr>
@@ -415,6 +415,8 @@ Exception Value: {{ exception_value|force_escape }}{% if exception_notes %}{{ ex
         {% endfor %}
       </tbody>
     </table>
+  {% elif request_FILES_error %}
+     <p>{{ request_FILES_error }}</p>
   {% else %}
     <p>No FILES data</p>
   {% endif %}

Where request_FILES_error is the error if available and "" or None otherwise

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

Comment on lines 438 to 439
"Number of GET paramters exceeded "
"DATA_UPLOAD_MAX_NUMBER_FIELDS.",
Copy link
Contributor

Choose a reason for hiding this comment

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

I think instead of us defining new text, we can use the text from the error itself (note there is a typo here)

@@ -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")
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
raise Exception("Test exception to trigger debug view")
raise Exception

This change is not needed

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