summaryrefslogtreecommitdiff
path: root/django/middleware/exception.py
blob: 437a82cf26516b09232e59086290e846f7e0c610 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
from __future__ import unicode_literals

import logging
import sys

from django.conf import settings
from django.core import signals
from django.core.exceptions import PermissionDenied, SuspiciousOperation
from django.http import Http404
from django.http.multipartparser import MultiPartParserError
from django.urls import get_resolver, get_urlconf
from django.utils.encoding import force_text
from django.views import debug

logger = logging.getLogger('django.request')


class ExceptionMiddleware(object):
    """
    Convert selected exceptions to HTTP responses.

    For example, convert Http404 to a 404 response either through handler404
    or through the debug view if settings.DEBUG=True. To ensure that
    exceptions raised by other middleware are converted to the appropriate
    response, this middleware is always automatically applied as the outermost
    middleware.
    """
    def __init__(self, get_response, handler=None):
        from django.core.handlers.base import BaseHandler
        self.get_response = get_response
        self.handler = handler or BaseHandler()

    def __call__(self, request):
        try:
            response = self.get_response(request)
        except Http404 as exc:
            if settings.DEBUG:
                response = debug.technical_404_response(request, exc)
            else:
                response = self.handler.get_exception_response(request, get_resolver(get_urlconf()), 404, exc)

        except PermissionDenied as exc:
            logger.warning(
                'Forbidden (Permission denied): %s', request.path,
                extra={'status_code': 403, 'request': request},
            )
            response = self.handler.get_exception_response(request, get_resolver(get_urlconf()), 403, exc)

        except MultiPartParserError as exc:
            logger.warning(
                'Bad request (Unable to parse request body): %s', request.path,
                extra={'status_code': 400, 'request': request},
            )
            response = self.handler.get_exception_response(request, get_resolver(get_urlconf()), 400, exc)

        except SuspiciousOperation as exc:
            # The request logger receives events for any problematic request
            # The security logger receives events for all SuspiciousOperations
            security_logger = logging.getLogger('django.security.%s' % exc.__class__.__name__)
            security_logger.error(
                force_text(exc),
                extra={'status_code': 400, 'request': request},
            )
            if settings.DEBUG:
                return debug.technical_500_response(request, *sys.exc_info(), status_code=400)

            response = self.handler.get_exception_response(request, get_resolver(get_urlconf()), 400, exc)

        except SystemExit:
            # Allow sys.exit() to actually exit. See tickets #1023 and #4701
            raise

        except Exception:  # Handle everything else.
            # Get the exception info now, in case another exception is thrown later.
            signals.got_request_exception.send(sender=self.handler.__class__, request=request)
            response = self.handler.handle_uncaught_exception(request, get_resolver(get_urlconf()), sys.exc_info())

        return response