Code

Opened 4 years ago

Closed 13 months ago

Last modified 13 months ago

#12250 closed Bug (wontfix)

process_view middleware prevents process_exception handling

Reported by: manfre Owned by: manfre
Component: Core (Other) Version: master
Severity: Normal Keywords: middleware
Cc: wdoekes Triage Stage: Design decision needed
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

If process_view() calls a view that raises and exception, it is handled by django.core.handlers.base.BaseHandler.handle_uncaught_exception() instead of being passed to the middleware for process_exception() handling.

Attachments (3)

django-base-handlers-view-middleware.patch (1.2 KB) - added by manfre 4 years ago.
django-base-handlers-view-middleware-with-tests.diff (7.0 KB) - added by manfre 4 years ago.
Patch against trunk rev 13959
12250.1.diff (5.8 KB) - added by ramiro 3 years ago.
Patch modified and simplfied

Download all attachments as: .zip

Change History (20)

Changed 4 years ago by manfre

comment:1 Changed 4 years ago by jdunck

  • Needs documentation unset
  • Needs tests set
  • Owner changed from nobody to jdunck
  • Patch needs improvement set
  • Status changed from new to assigned
  • Triage Stage changed from Unreviewed to Accepted

comment:2 Changed 4 years ago by jdunck

  • Keywords middleware added
  • Owner changed from jdunck to nobody
  • Status changed from assigned to new

comment:3 Changed 4 years ago by jdunck

This really needs tests. It's a critical piece of code and there are lots of exception paths around there.

comment:4 Changed 4 years ago by anonymous

  • Needs tests unset
  • Owner changed from nobody to anonymous
  • Patch needs improvement unset
  • Status changed from new to assigned

Changed 4 years ago by manfre

Patch against trunk rev 13959

comment:5 Changed 4 years ago by manfre

  • milestone set to 1.3
  • Owner changed from anonymous to manfre
  • Status changed from assigned to new

Updated the patch against trunk and hoping to get this in to 1.3

comment:6 Changed 3 years ago by ramiro

  • Triage Stage changed from Accepted to Design decision needed

So the ticket originally was about exceptions generated in the view itself not being caught an processed by .process_exception().

But the code modification and accompanying tests proposed aren't about exceptions in the view but exceptions originated in a middleware process_view() method.

The first is no longer an issue (I suspect it was fixed in r14393 and r14938) and the second one still happens but I'm not sure the change of behavior in that case should happen. I'm adding a modified and simplified patch demonstrating both scenarios.

Because of that, I'm moving this to design decision needed.

Version 0, edited 3 years ago by ramiro (next)

Changed 3 years ago by ramiro

Patch modified and simplfied

comment:7 Changed 3 years ago by mattmcc

  • milestone 1.3 deleted
  • Severity set to Normal
  • Type set to Bug

comment:8 Changed 2 years ago by aaugustin

  • UI/UX unset

Change UI/UX from NULL to False.

comment:9 Changed 2 years ago by aaugustin

  • Easy pickings unset

Change Easy pickings from NULL to False.

comment:10 Changed 21 months ago by kevin1024

I think the latest patch is missing the actual behavior modification. It seems to only have tests in it.

comment:11 Changed 15 months ago by wdoekes

  • Cc wdoekes added
126	+        """
127	+        A <Middleware>.process_view() that generates an exception and another
128	+        middleware whose process_exception() provides a response. Result should
129	+        be that response.
130	+        """
131	+        settings.MIDDLEWARE_CLASSES = (
132	+            'regressiontests.base_handler.middleware.ProcessViewRaise',
133	+            'regressiontests.base_handler.middleware.ProcessExceptionResponse',
134	+        )

Well, I have a common scenario that would benefit from having the exception handler handle the process_view() exception:

django/middleware/csrf.py

calls

    request_csrf_token = request.POST.get('csrfmiddlewaretoken', '')
...
    self._load_post_and_files()
...
    return self._stream.read(*args, **kwargs)

IOError: error reading wsgi.input data

I'd love to ignore that particular IOError, and I can, when it's generated in the view. But I can't when it's generated in the CSRF process_view.

As for how: I'd expect it to be handled just as if it was an exception in the view itself. I.e. surround the _view_middleware calls with a try/except just like the "response = callback(...)" bit.

Regards,
Walter Doekes

comment:12 Changed 15 months ago by akaariai

Another similar issue exists in process_request(). Consider case:

MIDDLEWARE_CLASSES = [
    'TransactionMiddleware',
    'SavesToDB',
    'RaisesException'
]

What happens is that TransactionMiddleware will open a transaction in process_request, savestodb will save to db and then RaisesException will raise an exception. The process_exceptions aren't called in this case. Finally process_response is called for every of the middlewares and thus TranscationMiddleware will commit the transaction. This is not good.

I see two solutions here - either we do the process_exception() dance for all middlewares for which process_request has been called (in process_view() case this means every middleware). Or, we decide that process_* should not ever raise an exception, and we go to panic mode if this happens. The panic mode would mean that we would try to release all resources (close connections etc) and then return a barebone 500 response.

To me the panic mode doesn't seem like a good idea.

I reported this in #19648. I marked that ticket as a duplicate of this one.

comment:13 Changed 13 months ago by aaugustin

This is almost the same problem as #16367 which I closed as wontfix.

Given the amount of discussion above, I'm not going to close as wontfix right now, but that's still my inclination.

comment:14 Changed 13 months ago by aaugustin

#12909 was closed as a duplicate.

comment:15 Changed 13 months ago by aaugustin

  • Resolution set to wontfix
  • Status changed from new to closed

Overall, the current design of the request handler assumes that middleware methods won't raise exceptions. They must deal with their own exceptions. Exceptions raised by middleware will end up in handle_uncaught_exception and produce a 500.

This may have some drawbacks, but at least it's consistent. Aborting on the first exception also avoids the problem of deciding which middleware should or shouldn't run after the first exception.

I could consider a different behavior, but that would require a global proposal for consistent exception handling in middleware. It seems quite tricky to design something that is useful, consistent, and simple.

I'm going to close this ticket because it's a piecewise approach of the problem that introduces some inconsistency.

comment:16 Changed 13 months ago by wdoekes

Should I create a new ticket for the unhandled exception in the csrf middleware then? :)

comment:17 Changed 13 months ago by aaugustin

Yes please. Sorry, I missed that in the comments.

Add Comment

Modify Ticket

Change Properties
<Author field>
Action
as closed
as The resolution will be set. Next status will be 'closed'
The resolution will be deleted. Next status will be 'new'
Author


E-mail address and user name can be saved in the Preferences.

 
Note: See TracTickets for help on using tickets.