Commit e277301c authored by Claude Paroz's avatar Claude Paroz
Browse files

Fixed #19387 -- Preserved SafeData status in contrib.messages

Thanks Anton Baklanov for the report and the patch.
parent 4007c8f6
Loading
Loading
Loading
Loading
+7 −2
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@ from django.conf import settings
from django.contrib.messages.storage.base import BaseStorage, Message
from django.http import SimpleCookie
from django.utils.crypto import salted_hmac, constant_time_compare
from django.utils.safestring import SafeData, mark_safe
from django.utils import six


@@ -15,7 +16,9 @@ class MessageEncoder(json.JSONEncoder):

    def default(self, obj):
        if isinstance(obj, Message):
            message = [self.message_key, obj.level, obj.message]
            # Using 0/1 here instead of False/True to produce more compact json
            is_safedata = 1 if isinstance(obj.message, SafeData) else 0
            message = [self.message_key, is_safedata, obj.level, obj.message]
            if obj.extra_tags:
                message.append(obj.extra_tags)
            return message
@@ -30,7 +33,9 @@ class MessageDecoder(json.JSONDecoder):
    def process_messages(self, obj):
        if isinstance(obj, list) and obj:
            if obj[0] == MessageEncoder.message_key:
                return Message(*obj[1:])
                if obj[1]:
                    obj[3] = mark_safe(obj[3])
                return Message(*obj[2:])
            return [self.process_messages(item) for item in obj]
        if isinstance(obj, dict):
            return dict([(key, self.process_messages(value))
+19 −0
Original line number Diff line number Diff line
@@ -6,6 +6,7 @@ from django.contrib.messages.storage.cookie import (CookieStorage,
    MessageEncoder, MessageDecoder)
from django.contrib.messages.storage.base import Message
from django.test.utils import override_settings
from django.utils.safestring import SafeData, mark_safe


def set_cookie_data(storage, messages, invalid=False, encode_empty=False):
@@ -132,3 +133,21 @@ class CookieTest(BaseTest):
        value = encoder.encode(messages)
        decoded_messages = json.loads(value, cls=MessageDecoder)
        self.assertEqual(messages, decoded_messages)

    def test_safedata(self):
        """
        Tests that a message containing SafeData is keeping its safe status when
        retrieved from the message storage.
        """
        def encode_decode(data):
            message = Message(constants.DEBUG, data)
            encoded = storage._encode(message)
            decoded = storage._decode(encoded)
            return decoded.message

        storage = self.get_storage()

        self.assertIsInstance(
            encode_decode(mark_safe("<b>Hello Django!</b>")), SafeData)
        self.assertNotIsInstance(
            encode_decode("<b>Hello Django!</b>"), SafeData)
+14 −0
Original line number Diff line number Diff line
from django.contrib.messages import constants
from django.contrib.messages.tests.base import BaseTest
from django.contrib.messages.storage.base import Message
from django.contrib.messages.storage.session import SessionStorage
from django.utils.safestring import SafeData, mark_safe


def set_session_data(storage, messages):
@@ -36,3 +39,14 @@ class SessionTest(BaseTest):
        set_session_data(storage, example_messages)
        # Test that the message actually contains what we expect.
        self.assertEqual(list(storage), example_messages)

    def test_safedata(self):
        """
        Tests that a message containing SafeData is keeping its safe status when
        retrieved from the message storage.
        """
        storage = self.get_storage()

        message = Message(constants.DEBUG, mark_safe("<b>Hello Django!</b>"))
        set_session_data(storage, [message])
        self.assertIsInstance(list(storage)[0].message, SafeData)