Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Fixed #16674 -- Pass exceptions to WSGI callback #133

Closed
wants to merge 1 commit into from

2 participants

@chrisglass

This patch is a attempt at making the patch attached to
https://code.djangoproject.com/ticket/16674 more github friendly, and adds
tests.

It passes raised exceptions to the WSGI start_response callback, so that
WSGI middlewares can track, log or otherwise handle excpetions (as is
done in other WSGI compliant applications, and as specified in PEP 3333).

Thanks to "jamesh" for the original fix.

@chrisglass chrisglass Fixed #16674 -- Pass exceptions to WSGI callback
This patch is a attempt at making the patch attached to
https://code.djangoproject.com/ticket/16674 more github friendly.

It passes raised exceptions to the WSGI start_response callback, so that
WSGI middlewares can track, log or otherwise handle excpetions (as is
done in other WSGI compliant applications).

Thanks to "jamesh" for the original fix.

Added myself to AUTHORS
af8733f
@aaugustin
Owner

This PR is stale. Since our triage options on GitHub are limited to "open" or "closed", I'm going to close it. Please re-open if you have a chance to update it.

If no one reviews it, write to the django-developers mailing list. Thanks!

@aaugustin aaugustin closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jun 12, 2012
  1. @chrisglass

    Fixed #16674 -- Pass exceptions to WSGI callback

    chrisglass authored
    This patch is a attempt at making the patch attached to
    https://code.djangoproject.com/ticket/16674 more github friendly.
    
    It passes raised exceptions to the WSGI start_response callback, so that
    WSGI middlewares can track, log or otherwise handle excpetions (as is
    done in other WSGI compliant applications).
    
    Thanks to "jamesh" for the original fix.
    
    Added myself to AUTHORS
This page is out of date. Refresh to see the latest.
View
1  AUTHORS
@@ -571,6 +571,7 @@ answer newbie questions, and generally made Django that much better:
Gasper Zejn <zejn@kiberpipa.org>
Jarek Zgoda <jarek.zgoda@gmail.com>
Cheng Zhang
+ Christopher Glass <tribaal@gmail.com>
A big THANK YOU goes to:
View
25 django/core/handlers/wsgi.py
@@ -151,6 +151,7 @@ def __init__(self, environ):
content_length = 0
self._stream = LimitedStream(self.environ['wsgi.input'], content_length)
self._read_started = False
+ self._wsgi_exc_info = None
def get_full_path(self):
# RFC 3986 requires query string arguments to be in the ASCII range.
@@ -225,19 +226,25 @@ def __call__(self, environ, start_response):
set_script_prefix(base.get_script_name(environ))
signals.request_started.send(sender=self.__class__)
+ exc_info = None
try:
try:
request = self.request_class(environ)
except UnicodeDecodeError:
+ exc_info = sys.exc_info()
logger.warning('Bad Request (UnicodeDecodeError)',
- exc_info=sys.exc_info(),
+ exc_info=exc_info,
extra={
'status_code': 400,
}
)
response = http.HttpResponseBadRequest()
else:
- response = self.get_response(request)
+ try:
+ response = self.get_response(request)
+ finally:
+ exc_info = request._wsgi_exc_info
+ request._wsgi_exc_info = None
finally:
signals.request_finished.send(sender=self.__class__)
@@ -249,5 +256,17 @@ def __call__(self, environ, start_response):
response_headers = [(str(k), str(v)) for k, v in response.items()]
for c in response.cookies.values():
response_headers.append((b'Set-Cookie', str(c.output(header=''))))
- start_response(smart_str(status), response_headers)
+ try:
+ start_response(smart_str(status), response_headers, exc_info)
+ finally:
+ exc_info = None
return response
+
+ def handle_uncaught_exception(self, request, resolver, exc_info):
+ # Capture the exception context so we can pass it back to __call__()
+ request._wsgi_exc_info = exc_info
+ try:
+ return super(WSGIHandler, self).handle_uncaught_exception(
+ request, resolver, exc_info)
+ finally:
+ exc_info = None
View
22 tests/regressiontests/wsgi/tests.py
@@ -16,7 +16,6 @@ def test_get_wsgi_application(self):
"""
Verify that ``get_wsgi_application`` returns a functioning WSGI
callable.
-
"""
application = get_wsgi_application()
@@ -28,7 +27,8 @@ def test_get_wsgi_application(self):
response_data = {}
- def start_response(status, headers):
+ def start_response(status, headers, exc_info=None):
+ # exc_info should be optional as per PEP 3333
response_data["status"] = status
response_data["headers"] = headers
@@ -42,6 +42,24 @@ def start_response(status, headers):
unicode(response),
"Content-Type: text/html; charset=utf-8\n\nHello World!")
+ def test_wsgi_exception_handling(self):
+ """
+ Verify that exceptions are passed to the user-supplied
+ ``start_response`` callback.
+ """
+ application = get_wsgi_application()
+ environ = RequestFactory()._base_environ(
+ PATH_INFO="/exception",
+ CONTENT_TYPE="text/html; charset=utf-8",
+ REQUEST_METHOD="GET"
+ )
+
+ def start_response(status, headers, exc_info=None):
+ # exc_info should be optional as per PEP 3333
+ self.assertNotEqual(exc_info, None)
+
+ application(environ, start_response)
+
class GetInternalWSGIApplicationTest(unittest.TestCase):
@override_settings(WSGI_APPLICATION="regressiontests.wsgi.wsgi.application")
View
6 tests/regressiontests/wsgi/urls.py
@@ -4,7 +4,11 @@
def helloworld(request):
return HttpResponse("Hello World!")
+def will_raise(request):
+ raise Exception()
+
urlpatterns = patterns(
"",
- url("^$", helloworld)
+ url("^$", helloworld),
+ url("^exception$", will_raise)
)
Something went wrong with that request. Please try again.