mirror of
https://github.com/django/django.git
synced 2025-04-01 03:56:42 +00:00
Refs #28948 -- Precomputed once serialized cookie messages.
When the cookie size is too long, the same messages were serialized over and over again.
This commit is contained in:
parent
67208a5ad6
commit
9d0c878abf
@ -47,14 +47,28 @@ class MessageDecoder(json.JSONDecoder):
|
|||||||
return self.process_messages(decoded)
|
return self.process_messages(decoded)
|
||||||
|
|
||||||
|
|
||||||
class MessageSerializer:
|
class MessagePartSerializer:
|
||||||
def dumps(self, obj):
|
def dumps(self, obj):
|
||||||
return json.dumps(
|
return [
|
||||||
obj,
|
json.dumps(
|
||||||
separators=(",", ":"),
|
o,
|
||||||
cls=MessageEncoder,
|
separators=(",", ":"),
|
||||||
).encode("latin-1")
|
cls=MessageEncoder,
|
||||||
|
)
|
||||||
|
for o in obj
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class MessagePartGatherSerializer:
|
||||||
|
def dumps(self, obj):
|
||||||
|
"""
|
||||||
|
The parameter is an already serialized list of Message objects. No need
|
||||||
|
to serialize it again, only join the list together and encode it.
|
||||||
|
"""
|
||||||
|
return ("[" + ",".join(obj) + "]").encode("latin-1")
|
||||||
|
|
||||||
|
|
||||||
|
class MessageSerializer:
|
||||||
def loads(self, data):
|
def loads(self, data):
|
||||||
return json.loads(data.decode("latin-1"), cls=MessageDecoder)
|
return json.loads(data.decode("latin-1"), cls=MessageDecoder)
|
||||||
|
|
||||||
@ -70,6 +84,7 @@ class CookieStorage(BaseStorage):
|
|||||||
# restrict the session cookie to 1/2 of 4kb. See #18781.
|
# restrict the session cookie to 1/2 of 4kb. See #18781.
|
||||||
max_cookie_size = 2048
|
max_cookie_size = 2048
|
||||||
not_finished = "__messagesnotfinished__"
|
not_finished = "__messagesnotfinished__"
|
||||||
|
not_finished_json = json.dumps("__messagesnotfinished__")
|
||||||
key_salt = "django.contrib.messages"
|
key_salt = "django.contrib.messages"
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
@ -122,7 +137,8 @@ class CookieStorage(BaseStorage):
|
|||||||
returned), and add the not_finished sentinel value to indicate as much.
|
returned), and add the not_finished sentinel value to indicate as much.
|
||||||
"""
|
"""
|
||||||
unstored_messages = []
|
unstored_messages = []
|
||||||
encoded_data = self._encode(messages)
|
serialized_messages = MessagePartSerializer().dumps(messages)
|
||||||
|
encoded_data = self._encode_parts(serialized_messages)
|
||||||
if self.max_cookie_size:
|
if self.max_cookie_size:
|
||||||
# data is going to be stored eventually by SimpleCookie, which
|
# data is going to be stored eventually by SimpleCookie, which
|
||||||
# adds its own overhead, which we must account for.
|
# adds its own overhead, which we must account for.
|
||||||
@ -134,27 +150,40 @@ class CookieStorage(BaseStorage):
|
|||||||
while encoded_data and stored_length(encoded_data) > self.max_cookie_size:
|
while encoded_data and stored_length(encoded_data) > self.max_cookie_size:
|
||||||
if remove_oldest:
|
if remove_oldest:
|
||||||
unstored_messages.append(messages.pop(0))
|
unstored_messages.append(messages.pop(0))
|
||||||
|
serialized_messages.pop(0)
|
||||||
else:
|
else:
|
||||||
unstored_messages.insert(0, messages.pop())
|
unstored_messages.insert(0, messages.pop())
|
||||||
encoded_data = self._encode(
|
serialized_messages.pop()
|
||||||
messages + [self.not_finished], encode_empty=unstored_messages
|
encoded_data = self._encode_parts(
|
||||||
|
serialized_messages + [self.not_finished_json],
|
||||||
|
encode_empty=bool(unstored_messages),
|
||||||
)
|
)
|
||||||
self._update_cookie(encoded_data, response)
|
self._update_cookie(encoded_data, response)
|
||||||
return unstored_messages
|
return unstored_messages
|
||||||
|
|
||||||
def _encode(self, messages, encode_empty=False):
|
def _encode_parts(self, messages, encode_empty=False):
|
||||||
"""
|
"""
|
||||||
Return an encoded version of the messages list which can be stored as
|
Return an encoded version of the serialized messages list which can be
|
||||||
plain text.
|
stored as plain text.
|
||||||
|
|
||||||
Since the data will be retrieved from the client-side, the encoded data
|
Since the data will be retrieved from the client-side, the encoded data
|
||||||
also contains a hash to ensure that the data was not tampered with.
|
also contains a hash to ensure that the data was not tampered with.
|
||||||
"""
|
"""
|
||||||
if messages or encode_empty:
|
if messages or encode_empty:
|
||||||
return self.signer.sign_object(
|
return self.signer.sign_object(
|
||||||
messages, serializer=MessageSerializer, compress=True
|
messages, serializer=MessagePartGatherSerializer, compress=True
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def _encode(self, messages, encode_empty=False):
|
||||||
|
"""
|
||||||
|
Return an encoded version of the messages list which can be stored as
|
||||||
|
plain text.
|
||||||
|
|
||||||
|
Proxies MessagePartSerializer.dumps and _encoded_parts.
|
||||||
|
"""
|
||||||
|
serialized_messages = MessagePartSerializer().dumps(messages)
|
||||||
|
return self._encode_parts(serialized_messages, encode_empty=encode_empty)
|
||||||
|
|
||||||
def _decode(self, data):
|
def _decode(self, data):
|
||||||
"""
|
"""
|
||||||
Safely decode an encoded text stream back into a list of messages.
|
Safely decode an encoded text stream back into a list of messages.
|
||||||
|
@ -60,9 +60,9 @@ class CookieTests(BaseTests, SimpleTestCase):
|
|||||||
|
|
||||||
def encode_decode(self, *args, **kwargs):
|
def encode_decode(self, *args, **kwargs):
|
||||||
storage = self.get_storage()
|
storage = self.get_storage()
|
||||||
message = Message(constants.DEBUG, *args, **kwargs)
|
message = [Message(constants.DEBUG, *args, **kwargs)]
|
||||||
encoded = storage._encode(message)
|
encoded = storage._encode(message)
|
||||||
return storage._decode(encoded)
|
return storage._decode(encoded)[0]
|
||||||
|
|
||||||
def test_get(self):
|
def test_get(self):
|
||||||
storage = self.storage_class(self.get_request())
|
storage = self.storage_class(self.get_request())
|
||||||
|
Loading…
x
Reference in New Issue
Block a user