Fixed #26688 -- Fixed HTTP request logging inconsistencies.
* Added logging of 500 responses for instantiated responses. * Added logging of all 4xx and 5xx responses.
This commit is contained in:
parent
2e1f674897
commit
10b44e4525
|
@ -5,6 +5,7 @@ from django.conf import settings
|
||||||
from django.core.exceptions import ImproperlyConfigured, MiddlewareNotUsed
|
from django.core.exceptions import ImproperlyConfigured, MiddlewareNotUsed
|
||||||
from django.db import connections, transaction
|
from django.db import connections, transaction
|
||||||
from django.urls import get_resolver, set_urlconf
|
from django.urls import get_resolver, set_urlconf
|
||||||
|
from django.utils.log import log_response
|
||||||
from django.utils.module_loading import import_string
|
from django.utils.module_loading import import_string
|
||||||
|
|
||||||
from .exception import convert_exception_to_response, get_exception_response
|
from .exception import convert_exception_to_response, get_exception_response
|
||||||
|
@ -87,10 +88,11 @@ class BaseHandler:
|
||||||
if not getattr(response, 'is_rendered', True) and callable(getattr(response, 'render', None)):
|
if not getattr(response, 'is_rendered', True) and callable(getattr(response, 'render', None)):
|
||||||
response = response.render()
|
response = response.render()
|
||||||
|
|
||||||
if response.status_code == 404:
|
if response.status_code >= 400:
|
||||||
logger.warning(
|
log_response(
|
||||||
'Not Found: %s', request.path,
|
'%s: %s', response.reason_phrase, request.path,
|
||||||
extra={'status_code': 404, 'request': request},
|
response=response,
|
||||||
|
request=request,
|
||||||
)
|
)
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
|
|
@ -11,10 +11,9 @@ from django.core.exceptions import (
|
||||||
from django.http import Http404
|
from django.http import Http404
|
||||||
from django.http.multipartparser import MultiPartParserError
|
from django.http.multipartparser import MultiPartParserError
|
||||||
from django.urls import get_resolver, get_urlconf
|
from django.urls import get_resolver, get_urlconf
|
||||||
|
from django.utils.log import log_response
|
||||||
from django.views import debug
|
from django.views import debug
|
||||||
|
|
||||||
logger = logging.getLogger('django.request')
|
|
||||||
|
|
||||||
|
|
||||||
def convert_exception_to_response(get_response):
|
def convert_exception_to_response(get_response):
|
||||||
"""
|
"""
|
||||||
|
@ -47,18 +46,22 @@ def response_for_exception(request, exc):
|
||||||
response = get_exception_response(request, get_resolver(get_urlconf()), 404, exc)
|
response = get_exception_response(request, get_resolver(get_urlconf()), 404, exc)
|
||||||
|
|
||||||
elif isinstance(exc, PermissionDenied):
|
elif isinstance(exc, PermissionDenied):
|
||||||
logger.warning(
|
|
||||||
'Forbidden (Permission denied): %s', request.path,
|
|
||||||
extra={'status_code': 403, 'request': request},
|
|
||||||
)
|
|
||||||
response = get_exception_response(request, get_resolver(get_urlconf()), 403, exc)
|
response = get_exception_response(request, get_resolver(get_urlconf()), 403, exc)
|
||||||
|
log_response(
|
||||||
|
'Forbidden (Permission denied): %s', request.path,
|
||||||
|
response=response,
|
||||||
|
request=request,
|
||||||
|
exc_info=sys.exc_info(),
|
||||||
|
)
|
||||||
|
|
||||||
elif isinstance(exc, MultiPartParserError):
|
elif isinstance(exc, MultiPartParserError):
|
||||||
logger.warning(
|
|
||||||
'Bad request (Unable to parse request body): %s', request.path,
|
|
||||||
extra={'status_code': 400, 'request': request},
|
|
||||||
)
|
|
||||||
response = get_exception_response(request, get_resolver(get_urlconf()), 400, exc)
|
response = get_exception_response(request, get_resolver(get_urlconf()), 400, exc)
|
||||||
|
log_response(
|
||||||
|
'Bad request (Unable to parse request body): %s', request.path,
|
||||||
|
response=response,
|
||||||
|
request=request,
|
||||||
|
exc_info=sys.exc_info(),
|
||||||
|
)
|
||||||
|
|
||||||
elif isinstance(exc, SuspiciousOperation):
|
elif isinstance(exc, SuspiciousOperation):
|
||||||
if isinstance(exc, (RequestDataTooBig, TooManyFieldsSent)):
|
if isinstance(exc, (RequestDataTooBig, TooManyFieldsSent)):
|
||||||
|
@ -85,6 +88,12 @@ def response_for_exception(request, exc):
|
||||||
else:
|
else:
|
||||||
signals.got_request_exception.send(sender=None, request=request)
|
signals.got_request_exception.send(sender=None, request=request)
|
||||||
response = handle_uncaught_exception(request, get_resolver(get_urlconf()), sys.exc_info())
|
response = handle_uncaught_exception(request, get_resolver(get_urlconf()), sys.exc_info())
|
||||||
|
log_response(
|
||||||
|
'%s: %s', response.reason_phrase, request.path,
|
||||||
|
response=response,
|
||||||
|
request=request,
|
||||||
|
exc_info=sys.exc_info(),
|
||||||
|
)
|
||||||
|
|
||||||
# Force a TemplateResponse to be rendered.
|
# Force a TemplateResponse to be rendered.
|
||||||
if not getattr(response, 'is_rendered', True) and callable(getattr(response, 'render', None)):
|
if not getattr(response, 'is_rendered', True) and callable(getattr(response, 'render', None)):
|
||||||
|
@ -112,12 +121,6 @@ def handle_uncaught_exception(request, resolver, exc_info):
|
||||||
if settings.DEBUG_PROPAGATE_EXCEPTIONS:
|
if settings.DEBUG_PROPAGATE_EXCEPTIONS:
|
||||||
raise
|
raise
|
||||||
|
|
||||||
logger.error(
|
|
||||||
'Internal Server Error: %s', request.path,
|
|
||||||
exc_info=exc_info,
|
|
||||||
extra={'status_code': 500, 'request': request},
|
|
||||||
)
|
|
||||||
|
|
||||||
if settings.DEBUG:
|
if settings.DEBUG:
|
||||||
return debug.technical_500_response(request, *exc_info)
|
return debug.technical_500_response(request, *exc_info)
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@ from django.utils.cache import patch_vary_headers
|
||||||
from django.utils.crypto import constant_time_compare, get_random_string
|
from django.utils.crypto import constant_time_compare, get_random_string
|
||||||
from django.utils.deprecation import MiddlewareMixin
|
from django.utils.deprecation import MiddlewareMixin
|
||||||
from django.utils.http import is_same_domain
|
from django.utils.http import is_same_domain
|
||||||
|
from django.utils.log import log_response
|
||||||
|
|
||||||
logger = logging.getLogger('django.security.csrf')
|
logger = logging.getLogger('django.security.csrf')
|
||||||
|
|
||||||
|
@ -146,14 +147,14 @@ class CsrfViewMiddleware(MiddlewareMixin):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def _reject(self, request, reason):
|
def _reject(self, request, reason):
|
||||||
logger.warning(
|
response = _get_failure_view()(request, reason=reason)
|
||||||
|
log_response(
|
||||||
'Forbidden (%s): %s', reason, request.path,
|
'Forbidden (%s): %s', reason, request.path,
|
||||||
extra={
|
response=response,
|
||||||
'status_code': 403,
|
request=request,
|
||||||
'request': request,
|
logger=logger,
|
||||||
}
|
|
||||||
)
|
)
|
||||||
return _get_failure_view()(request, reason=reason)
|
return response
|
||||||
|
|
||||||
def _get_token(self, request):
|
def _get_token(self, request):
|
||||||
if settings.CSRF_USE_SESSIONS:
|
if settings.CSRF_USE_SESSIONS:
|
||||||
|
|
|
@ -17,7 +17,6 @@ An example: i18n middleware would need to distinguish caches by the
|
||||||
"Accept-language" header.
|
"Accept-language" header.
|
||||||
"""
|
"""
|
||||||
import hashlib
|
import hashlib
|
||||||
import logging
|
|
||||||
import re
|
import re
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
@ -28,13 +27,12 @@ from django.utils.encoding import force_bytes, iri_to_uri
|
||||||
from django.utils.http import (
|
from django.utils.http import (
|
||||||
http_date, parse_etags, parse_http_date_safe, quote_etag,
|
http_date, parse_etags, parse_http_date_safe, quote_etag,
|
||||||
)
|
)
|
||||||
|
from django.utils.log import log_response
|
||||||
from django.utils.timezone import get_current_timezone_name
|
from django.utils.timezone import get_current_timezone_name
|
||||||
from django.utils.translation import get_language
|
from django.utils.translation import get_language
|
||||||
|
|
||||||
cc_delim_re = re.compile(r'\s*,\s*')
|
cc_delim_re = re.compile(r'\s*,\s*')
|
||||||
|
|
||||||
logger = logging.getLogger('django.request')
|
|
||||||
|
|
||||||
|
|
||||||
def patch_cache_control(response, **kwargs):
|
def patch_cache_control(response, **kwargs):
|
||||||
"""
|
"""
|
||||||
|
@ -106,14 +104,13 @@ def set_response_etag(response):
|
||||||
|
|
||||||
|
|
||||||
def _precondition_failed(request):
|
def _precondition_failed(request):
|
||||||
logger.warning(
|
response = HttpResponse(status=412)
|
||||||
|
log_response(
|
||||||
'Precondition Failed: %s', request.path,
|
'Precondition Failed: %s', request.path,
|
||||||
extra={
|
response=response,
|
||||||
'status_code': 412,
|
request=request,
|
||||||
'request': request,
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
return HttpResponse(status=412)
|
return response
|
||||||
|
|
||||||
|
|
||||||
def _not_modified(request, response=None):
|
def _not_modified(request, response=None):
|
||||||
|
|
|
@ -9,6 +9,8 @@ from django.core.management.color import color_style
|
||||||
from django.utils.module_loading import import_string
|
from django.utils.module_loading import import_string
|
||||||
from django.views.debug import ExceptionReporter
|
from django.views.debug import ExceptionReporter
|
||||||
|
|
||||||
|
request_logger = logging.getLogger('django.request')
|
||||||
|
|
||||||
# Default logging for Django. This sends an email to the site admins on every
|
# Default logging for Django. This sends an email to the site admins on every
|
||||||
# HTTP 500 error. Depending on DEBUG, all other log records are either sent to
|
# HTTP 500 error. Depending on DEBUG, all other log records are either sent to
|
||||||
# the console (DEBUG=True) or discarded (DEBUG=False) by means of the
|
# the console (DEBUG=True) or discarded (DEBUG=False) by means of the
|
||||||
|
@ -192,3 +194,37 @@ class ServerFormatter(logging.Formatter):
|
||||||
|
|
||||||
def uses_server_time(self):
|
def uses_server_time(self):
|
||||||
return self._fmt.find('{server_time}') >= 0
|
return self._fmt.find('{server_time}') >= 0
|
||||||
|
|
||||||
|
|
||||||
|
def log_response(message, *args, response=None, request=None, logger=request_logger, level=None, exc_info=None):
|
||||||
|
"""
|
||||||
|
Log errors based on HttpResponse status.
|
||||||
|
|
||||||
|
Log 5xx responses as errors and 4xx responses as warnings (unless a level
|
||||||
|
is given as a keyword argument). The HttpResponse status_code and the
|
||||||
|
request are passed to the logger's extra parameter.
|
||||||
|
"""
|
||||||
|
# Check if the response has already been logged. Multiple requests to log
|
||||||
|
# the same response can be received in some cases, e.g., when the
|
||||||
|
# response is the result of an exception and is logged at the time the
|
||||||
|
# exception is caught so that the exc_info can be recorded.
|
||||||
|
if getattr(response, '_has_been_logged', False):
|
||||||
|
return
|
||||||
|
|
||||||
|
if level is None:
|
||||||
|
if response.status_code >= 500:
|
||||||
|
level = 'error'
|
||||||
|
elif response.status_code >= 400:
|
||||||
|
level = 'warning'
|
||||||
|
else:
|
||||||
|
level = 'info'
|
||||||
|
|
||||||
|
getattr(logger, level)(
|
||||||
|
message, *args,
|
||||||
|
extra={
|
||||||
|
'status_code': response.status_code,
|
||||||
|
'request': request,
|
||||||
|
},
|
||||||
|
exc_info=exc_info,
|
||||||
|
)
|
||||||
|
response._has_been_logged = True
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
Decorators for views based on HTTP headers.
|
Decorators for views based on HTTP headers.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import logging
|
|
||||||
from calendar import timegm
|
from calendar import timegm
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
|
|
||||||
|
@ -11,11 +10,10 @@ from django.middleware.http import ConditionalGetMiddleware
|
||||||
from django.utils.cache import get_conditional_response
|
from django.utils.cache import get_conditional_response
|
||||||
from django.utils.decorators import decorator_from_middleware
|
from django.utils.decorators import decorator_from_middleware
|
||||||
from django.utils.http import http_date, quote_etag
|
from django.utils.http import http_date, quote_etag
|
||||||
|
from django.utils.log import log_response
|
||||||
|
|
||||||
conditional_page = decorator_from_middleware(ConditionalGetMiddleware)
|
conditional_page = decorator_from_middleware(ConditionalGetMiddleware)
|
||||||
|
|
||||||
logger = logging.getLogger('django.request')
|
|
||||||
|
|
||||||
|
|
||||||
def require_http_methods(request_method_list):
|
def require_http_methods(request_method_list):
|
||||||
"""
|
"""
|
||||||
|
@ -32,11 +30,13 @@ def require_http_methods(request_method_list):
|
||||||
@wraps(func)
|
@wraps(func)
|
||||||
def inner(request, *args, **kwargs):
|
def inner(request, *args, **kwargs):
|
||||||
if request.method not in request_method_list:
|
if request.method not in request_method_list:
|
||||||
logger.warning(
|
response = HttpResponseNotAllowed(request_method_list)
|
||||||
|
log_response(
|
||||||
'Method Not Allowed (%s): %s', request.method, request.path,
|
'Method Not Allowed (%s): %s', request.method, request.path,
|
||||||
extra={'status_code': 405, 'request': request}
|
response=response,
|
||||||
|
request=request,
|
||||||
)
|
)
|
||||||
return HttpResponseNotAllowed(request_method_list)
|
return response
|
||||||
return func(request, *args, **kwargs)
|
return func(request, *args, **kwargs)
|
||||||
return inner
|
return inner
|
||||||
return decorator
|
return decorator
|
||||||
|
|
|
@ -468,7 +468,8 @@ posted using this name but instead using one of the loggers below.
|
||||||
|
|
||||||
Log messages related to the handling of requests. 5XX responses are
|
Log messages related to the handling of requests. 5XX responses are
|
||||||
raised as ``ERROR`` messages; 4XX responses are raised as ``WARNING``
|
raised as ``ERROR`` messages; 4XX responses are raised as ``WARNING``
|
||||||
messages.
|
messages. Requests that are logged to the ``django.security`` logger aren't
|
||||||
|
logged to ``django.request``.
|
||||||
|
|
||||||
Messages to this logger have the following extra context:
|
Messages to this logger have the following extra context:
|
||||||
|
|
||||||
|
|
|
@ -6,15 +6,18 @@ from admin_scripts.tests import AdminScriptTestCase
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core import mail
|
from django.core import mail
|
||||||
|
from django.core.exceptions import PermissionDenied
|
||||||
from django.core.files.temp import NamedTemporaryFile
|
from django.core.files.temp import NamedTemporaryFile
|
||||||
from django.core.management import color
|
from django.core.management import color
|
||||||
|
from django.http.multipartparser import MultiPartParserError
|
||||||
from django.test import RequestFactory, SimpleTestCase, override_settings
|
from django.test import RequestFactory, SimpleTestCase, override_settings
|
||||||
from django.test.utils import LoggingCaptureMixin, patch_logger
|
from django.test.utils import LoggingCaptureMixin
|
||||||
from django.utils.log import (
|
from django.utils.log import (
|
||||||
DEFAULT_LOGGING, AdminEmailHandler, CallbackFilter, RequireDebugFalse,
|
DEFAULT_LOGGING, AdminEmailHandler, CallbackFilter, RequireDebugFalse,
|
||||||
RequireDebugTrue, ServerFormatter,
|
RequireDebugTrue, ServerFormatter,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
from . import views
|
||||||
from .logconfig import MyEmailBackend
|
from .logconfig import MyEmailBackend
|
||||||
|
|
||||||
# logging config prior to using filter with mail_admins
|
# logging config prior to using filter with mail_admins
|
||||||
|
@ -106,16 +109,95 @@ class DefaultLoggingTests(SetupDefaultLoggingMixin, LoggingCaptureMixin, SimpleT
|
||||||
self.assertEqual(self.logger_output.getvalue(), '')
|
self.assertEqual(self.logger_output.getvalue(), '')
|
||||||
|
|
||||||
|
|
||||||
|
class LoggingAssertionMixin(object):
|
||||||
|
|
||||||
|
def assertLogsRequest(self, url, level, msg, status_code, logger='django.request', exc_class=None):
|
||||||
|
with self.assertLogs(logger, level) as cm:
|
||||||
|
try:
|
||||||
|
self.client.get(url)
|
||||||
|
except views.UncaughtException:
|
||||||
|
pass
|
||||||
|
self.assertEqual(
|
||||||
|
len(cm.records), 1,
|
||||||
|
"Wrong number of calls for logger %r in %r level." % (logger, level)
|
||||||
|
)
|
||||||
|
record = cm.records[0]
|
||||||
|
self.assertEqual(record.getMessage(), msg)
|
||||||
|
self.assertEqual(record.status_code, status_code)
|
||||||
|
if exc_class:
|
||||||
|
self.assertIsNotNone(record.exc_info)
|
||||||
|
self.assertEqual(record.exc_info[0], exc_class)
|
||||||
|
|
||||||
|
|
||||||
@override_settings(DEBUG=True, ROOT_URLCONF='logging_tests.urls')
|
@override_settings(DEBUG=True, ROOT_URLCONF='logging_tests.urls')
|
||||||
class HandlerLoggingTests(SetupDefaultLoggingMixin, LoggingCaptureMixin, SimpleTestCase):
|
class HandlerLoggingTests(SetupDefaultLoggingMixin, LoggingAssertionMixin, LoggingCaptureMixin, SimpleTestCase):
|
||||||
|
|
||||||
def test_page_found_no_warning(self):
|
def test_page_found_no_warning(self):
|
||||||
self.client.get('/innocent/')
|
self.client.get('/innocent/')
|
||||||
self.assertEqual(self.logger_output.getvalue(), '')
|
self.assertEqual(self.logger_output.getvalue(), '')
|
||||||
|
|
||||||
|
def test_redirect_no_warning(self):
|
||||||
|
self.client.get('/redirect/')
|
||||||
|
self.assertEqual(self.logger_output.getvalue(), '')
|
||||||
|
|
||||||
def test_page_not_found_warning(self):
|
def test_page_not_found_warning(self):
|
||||||
self.client.get('/does_not_exist/')
|
self.assertLogsRequest(
|
||||||
self.assertEqual(self.logger_output.getvalue(), 'Not Found: /does_not_exist/\n')
|
url='/does_not_exist/',
|
||||||
|
level='WARNING',
|
||||||
|
status_code=404,
|
||||||
|
msg='Not Found: /does_not_exist/',
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_page_not_found_raised(self):
|
||||||
|
self.assertLogsRequest(
|
||||||
|
url='/does_not_exist_raised/',
|
||||||
|
level='WARNING',
|
||||||
|
status_code=404,
|
||||||
|
msg='Not Found: /does_not_exist_raised/',
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_uncaught_exception(self):
|
||||||
|
self.assertLogsRequest(
|
||||||
|
url='/uncaught_exception/',
|
||||||
|
level='ERROR',
|
||||||
|
status_code=500,
|
||||||
|
msg='Internal Server Error: /uncaught_exception/',
|
||||||
|
exc_class=views.UncaughtException,
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_internal_server_error(self):
|
||||||
|
self.assertLogsRequest(
|
||||||
|
url='/internal_server_error/',
|
||||||
|
level='ERROR',
|
||||||
|
status_code=500,
|
||||||
|
msg='Internal Server Error: /internal_server_error/',
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_internal_server_error_599(self):
|
||||||
|
self.assertLogsRequest(
|
||||||
|
url='/internal_server_error/?status=599',
|
||||||
|
level='ERROR',
|
||||||
|
status_code=599,
|
||||||
|
msg='Unknown Status Code: /internal_server_error/',
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_permission_denied(self):
|
||||||
|
self.assertLogsRequest(
|
||||||
|
url='/permission_denied/',
|
||||||
|
level='WARNING',
|
||||||
|
status_code=403,
|
||||||
|
msg='Forbidden (Permission denied): /permission_denied/',
|
||||||
|
exc_class=PermissionDenied,
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_multi_part_parser_error(self):
|
||||||
|
self.assertLogsRequest(
|
||||||
|
url='/multi_part_parser_error/',
|
||||||
|
level='WARNING',
|
||||||
|
status_code=400,
|
||||||
|
msg='Bad request (Unable to parse request body): /multi_part_parser_error/',
|
||||||
|
exc_class=MultiPartParserError,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@override_settings(
|
@override_settings(
|
||||||
|
@ -401,19 +483,25 @@ class SetupConfigureLogging(SimpleTestCase):
|
||||||
|
|
||||||
|
|
||||||
@override_settings(DEBUG=True, ROOT_URLCONF='logging_tests.urls')
|
@override_settings(DEBUG=True, ROOT_URLCONF='logging_tests.urls')
|
||||||
class SecurityLoggerTest(SimpleTestCase):
|
class SecurityLoggerTest(LoggingAssertionMixin, SimpleTestCase):
|
||||||
|
|
||||||
def test_suspicious_operation_creates_log_message(self):
|
def test_suspicious_operation_creates_log_message(self):
|
||||||
with patch_logger('django.security.SuspiciousOperation', 'error') as calls:
|
self.assertLogsRequest(
|
||||||
self.client.get('/suspicious/')
|
url='/suspicious/',
|
||||||
self.assertEqual(len(calls), 1)
|
level='ERROR',
|
||||||
self.assertEqual(calls[0], 'dubious')
|
msg='dubious',
|
||||||
|
status_code=400,
|
||||||
|
logger='django.security.SuspiciousOperation',
|
||||||
|
)
|
||||||
|
|
||||||
def test_suspicious_operation_uses_sublogger(self):
|
def test_suspicious_operation_uses_sublogger(self):
|
||||||
with patch_logger('django.security.DisallowedHost', 'error') as calls:
|
self.assertLogsRequest(
|
||||||
self.client.get('/suspicious_spec/')
|
url='/suspicious_spec/',
|
||||||
self.assertEqual(len(calls), 1)
|
level='ERROR',
|
||||||
self.assertEqual(calls[0], 'dubious')
|
msg='dubious',
|
||||||
|
status_code=400,
|
||||||
|
logger='django.security.DisallowedHost',
|
||||||
|
)
|
||||||
|
|
||||||
@override_settings(
|
@override_settings(
|
||||||
ADMINS=[('admin', 'admin@example.com')],
|
ADMINS=[('admin', 'admin@example.com')],
|
||||||
|
|
|
@ -1,9 +1,16 @@
|
||||||
from django.conf.urls import url
|
from django.conf.urls import url
|
||||||
|
from django.urls import path
|
||||||
|
|
||||||
from . import views
|
from . import views
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
url(r'^innocent/$', views.innocent),
|
url(r'^innocent/$', views.innocent),
|
||||||
|
path('redirect/', views.redirect),
|
||||||
url(r'^suspicious/$', views.suspicious),
|
url(r'^suspicious/$', views.suspicious),
|
||||||
url(r'^suspicious_spec/$', views.suspicious_spec),
|
url(r'^suspicious_spec/$', views.suspicious_spec),
|
||||||
|
path('internal_server_error/', views.internal_server_error),
|
||||||
|
path('uncaught_exception/', views.uncaught_exception),
|
||||||
|
path('permission_denied/', views.permission_denied),
|
||||||
|
path('multi_part_parser_error/', views.multi_part_parser_error),
|
||||||
|
path('does_not_exist_raised/', views.does_not_exist_raised),
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,14 +1,48 @@
|
||||||
from django.core.exceptions import DisallowedHost, SuspiciousOperation
|
from django.core.exceptions import (
|
||||||
from django.http import HttpResponse
|
DisallowedHost, PermissionDenied, SuspiciousOperation,
|
||||||
|
)
|
||||||
|
from django.http import (
|
||||||
|
Http404, HttpResponse, HttpResponseRedirect, HttpResponseServerError,
|
||||||
|
)
|
||||||
|
from django.http.multipartparser import MultiPartParserError
|
||||||
|
|
||||||
|
|
||||||
def innocent(request):
|
def innocent(request):
|
||||||
return HttpResponse('innocent')
|
return HttpResponse('innocent')
|
||||||
|
|
||||||
|
|
||||||
|
def redirect(request):
|
||||||
|
return HttpResponseRedirect('/')
|
||||||
|
|
||||||
|
|
||||||
def suspicious(request):
|
def suspicious(request):
|
||||||
raise SuspiciousOperation('dubious')
|
raise SuspiciousOperation('dubious')
|
||||||
|
|
||||||
|
|
||||||
def suspicious_spec(request):
|
def suspicious_spec(request):
|
||||||
raise DisallowedHost('dubious')
|
raise DisallowedHost('dubious')
|
||||||
|
|
||||||
|
|
||||||
|
class UncaughtException(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def uncaught_exception(request):
|
||||||
|
raise UncaughtException('Uncaught exception')
|
||||||
|
|
||||||
|
|
||||||
|
def internal_server_error(request):
|
||||||
|
status = request.GET.get('status', 500)
|
||||||
|
return HttpResponseServerError('Server Error', status=int(status))
|
||||||
|
|
||||||
|
|
||||||
|
def permission_denied(request):
|
||||||
|
raise PermissionDenied()
|
||||||
|
|
||||||
|
|
||||||
|
def multi_part_parser_error(request):
|
||||||
|
raise MultiPartParserError('parsing error')
|
||||||
|
|
||||||
|
|
||||||
|
def does_not_exist_raised(request):
|
||||||
|
raise Http404('Not Found')
|
||||||
|
|
Loading…
Reference in New Issue