Commit 21bf685f authored by Iacopo Spalletti's avatar Iacopo Spalletti Committed by Tim Graham
Browse files

Fixed #25697 -- Made default error views error when passed a nonexistent template_name.

parent 8d5d472c
Loading
Loading
Loading
Loading
+21 −4
Original line number Diff line number Diff line
@@ -4,12 +4,17 @@ from django.utils import six
from django.utils.encoding import force_text
from django.views.decorators.csrf import requires_csrf_token

ERROR_404_TEMPLATE_NAME = '404.html'
ERROR_403_TEMPLATE_NAME = '403.html'
ERROR_400_TEMPLATE_NAME = '400.html'
ERROR_500_TEMPLATE_NAME = '500.html'


# This can be called when CsrfViewMiddleware.process_view has not run,
# therefore need @requires_csrf_token in case the template needs
# {% csrf_token %}.
@requires_csrf_token
def page_not_found(request, exception, template_name='404.html'):
def page_not_found(request, exception, template_name=ERROR_404_TEMPLATE_NAME):
    """
    Default 404 handler.

@@ -40,6 +45,9 @@ def page_not_found(request, exception, template_name='404.html'):
        body = template.render(context, request)
        content_type = None             # Django will use DEFAULT_CONTENT_TYPE
    except TemplateDoesNotExist:
        if template_name != ERROR_404_TEMPLATE_NAME:
            # Reraise if it's a missing custom template.
            raise
        template = Engine().from_string(
            '<h1>Not Found</h1>'
            '<p>The requested URL {{ request_path }} was not found on this server.</p>')
@@ -49,7 +57,7 @@ def page_not_found(request, exception, template_name='404.html'):


@requires_csrf_token
def server_error(request, template_name='500.html'):
def server_error(request, template_name=ERROR_500_TEMPLATE_NAME):
    """
    500 error handler.

@@ -59,12 +67,15 @@ def server_error(request, template_name='500.html'):
    try:
        template = loader.get_template(template_name)
    except TemplateDoesNotExist:
        if template_name != ERROR_500_TEMPLATE_NAME:
            # Reraise if it's a missing custom template.
            raise
        return http.HttpResponseServerError('<h1>Server Error (500)</h1>', content_type='text/html')
    return http.HttpResponseServerError(template.render())


@requires_csrf_token
def bad_request(request, exception, template_name='400.html'):
def bad_request(request, exception, template_name=ERROR_400_TEMPLATE_NAME):
    """
    400 error handler.

@@ -74,6 +85,9 @@ def bad_request(request, exception, template_name='400.html'):
    try:
        template = loader.get_template(template_name)
    except TemplateDoesNotExist:
        if template_name != ERROR_400_TEMPLATE_NAME:
            # Reraise if it's a missing custom template.
            raise
        return http.HttpResponseBadRequest('<h1>Bad Request (400)</h1>', content_type='text/html')
    # No exception content is passed to the template, to not disclose any sensitive information.
    return http.HttpResponseBadRequest(template.render())
@@ -83,7 +97,7 @@ def bad_request(request, exception, template_name='400.html'):
# therefore need @requires_csrf_token in case the template needs
# {% csrf_token %}.
@requires_csrf_token
def permission_denied(request, exception, template_name='403.html'):
def permission_denied(request, exception, template_name=ERROR_403_TEMPLATE_NAME):
    """
    Permission denied (403) handler.

@@ -96,6 +110,9 @@ def permission_denied(request, exception, template_name='403.html'):
    try:
        template = loader.get_template(template_name)
    except TemplateDoesNotExist:
        if template_name != ERROR_403_TEMPLATE_NAME:
            # Reraise if it's a missing custom template.
            raise
        return http.HttpResponseForbidden('<h1>403 Forbidden</h1>', content_type='text/html')
    return http.HttpResponseForbidden(
        template.render(request=request, context={'exception': force_text(exception)})
+16 −0
Original line number Diff line number Diff line
@@ -93,6 +93,10 @@ Three things to note about 404 views:
    second parameter, the exception that triggered the error. A useful
    representation of the exception is also passed in the template context.

.. versionchanged:: 1.10

    Passing a nonexistent ``template_name`` will raise ``TemplateDoesNotExist``.

.. _http_internal_server_error_view:

The 500 (server error) view
@@ -113,6 +117,10 @@ If :setting:`DEBUG` is set to ``True`` (in your settings module), then
your 500 view will never be used, and the traceback will be displayed
instead, with some debug information.

.. versionchanged:: 1.10

    Passing a nonexistent ``template_name`` will raise ``TemplateDoesNotExist``.

.. _http_forbidden_view:

The 403 (HTTP Forbidden) view
@@ -148,6 +156,10 @@ view you can use code like this::
    unicode representation of the exception is also passed in the template
    context.

.. versionchanged:: 1.10

    Passing a nonexistent ``template_name`` will raise ``TemplateDoesNotExist``.

.. _http_bad_request_view:

The 400 (bad request) view
@@ -173,3 +185,7 @@ filesystem paths.

    The signature of ``bad_request()`` changed in Django 1.9. The function
    now accepts a second parameter, the exception that triggered the error.

.. versionchanged:: 1.10

    Passing a nonexistent ``template_name`` will raise ``TemplateDoesNotExist``.
+3 −0
Original line number Diff line number Diff line
@@ -464,6 +464,9 @@ Miscellaneous
  now better to call the ``LogEntry.get_change_message()`` method which will
  provide the message in the current language.

* The default error views now raise ``TemplateDoesNotExist`` if a nonexistent
  ``template_name`` is specified.

.. _deprecated-features-1.10:

Features deprecated in 1.10
+26 −1
Original line number Diff line number Diff line
@@ -4,8 +4,13 @@ import datetime

from django.contrib.auth.models import User
from django.contrib.sites.models import Site
from django.test import TestCase
from django.http import Http404
from django.template import TemplateDoesNotExist
from django.test import RequestFactory, TestCase
from django.test.utils import override_settings
from django.views.defaults import (
    bad_request, page_not_found, permission_denied, server_error,
)

from ..models import Article, Author, UrlArticle

@@ -123,3 +128,23 @@ class DefaultsTests(TestCase):

        response = self.client.get('/server_error/')
        self.assertEqual(response['Content-Type'], 'text/html')

    def test_custom_templates_wrong(self):
        """
        Default error views should raise TemplateDoesNotExist when passed a
        template that doesn't exist.
        """
        rf = RequestFactory()
        request = rf.get('/')

        with self.assertRaises(TemplateDoesNotExist):
            bad_request(request, Exception(), template_name='nonexistent')

        with self.assertRaises(TemplateDoesNotExist):
            permission_denied(request, Exception(), template_name='nonexistent')

        with self.assertRaises(TemplateDoesNotExist):
            page_not_found(request, Http404(), template_name='nonexistent')

        with self.assertRaises(TemplateDoesNotExist):
            server_error(request, template_name='nonexistent')