Commit 63058786 authored by James Bennett's avatar James Bennett
Browse files

Merge pull request #2967 from hirokiky/fix23070

Fixed #23070 -- not to break the debug page by callable setting with __slots__
parents 6eed7511 d0889863
Loading
Loading
Loading
Loading
+15 −1
Original line number Diff line number Diff line
@@ -33,6 +33,19 @@ def linebreak_iter(template_source):
    yield len(template_source) + 1


class CallableSettingWrapper(object):
    """ Object to wrap callable appearing in settings

    * Not to call in the debug page (#21345).
    * Not to break the debug page if the callable forbidding to set attributes (#23070).
    """
    def __init__(self, callable_setting):
        self._wrapped = callable_setting

    def __repr__(self):
        return repr(self._wrapped)


def cleanse_setting(key, value):
    """Cleanse an individual setting key/value of sensitive content.

@@ -52,7 +65,8 @@ def cleanse_setting(key, value):
        cleansed = value

    if callable(cleansed):
        cleansed.do_not_call_in_templates = True
        # For fixing #21345 and #23070
        cleansed = CallableSettingWrapper(cleansed)

    return cleansed

+31 −1
Original line number Diff line number Diff line
@@ -20,7 +20,7 @@ from django.test import TestCase, RequestFactory, override_settings
from django.test.utils import override_with_test_loader
from django.utils.encoding import force_text, force_bytes
from django.utils import six
from django.views.debug import ExceptionReporter
from django.views.debug import CallableSettingWrapper, ExceptionReporter

from .. import BrokenException, except_args
from ..views import (sensitive_view, non_sensitive_view, paranoid_view,
@@ -29,6 +29,21 @@ from ..views import (sensitive_view, non_sensitive_view, paranoid_view,
    multivalue_dict_key_error)


class CallableSettingWrapperTests(TestCase):
    """ Unittests for CallableSettingWrapper
    """
    def test_repr(self):
        class WrappedCallable(object):
            def __repr__(self):
                return "repr from the wrapped callable"

            def __call__(self):
                pass

        actual = repr(CallableSettingWrapper(WrappedCallable()))
        self.assertEqual(actual, "repr from the wrapped callable")


@override_settings(DEBUG=True, TEMPLATE_DEBUG=True,
                   ROOT_URLCONF="view_tests.urls")
class DebugViewTests(TestCase):
@@ -660,6 +675,21 @@ class ExceptionReporterFilterTests(TestCase, ExceptionReportTestMixin):
            response = self.client.get('/raises500/')
            self.assertNotContains(response, "This should not be displayed", status_code=500)

    def test_callable_settings_forbidding_to_set_attributes(self):
        """
        Callable settings which forbid to set attributes should not break
        the debug page (#23070).
        """
        class CallableSettingWithSlots(object):
            __slots__ = []

            def __call__(self):
                return "This should not be displayed"

        with self.settings(DEBUG=True, WITH_SLOTS=CallableSettingWithSlots()):
            response = self.client.get('/raises500/')
            self.assertNotContains(response, "This should not be displayed", status_code=500)

    def test_dict_setting_with_non_str_key(self):
        """
        A dict setting containing a non-string key should not break the