zmc
2023-12-22 9fdbf60165db0400c2e8e6be2dc6e88138ac719a
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
import typing as _t
import zlib
 
from ._json import _CompactJSON
from .encoding import base64_decode
from .encoding import base64_encode
from .exc import BadPayload
from .serializer import Serializer
from .timed import TimedSerializer
 
 
class URLSafeSerializerMixin(Serializer):
    """Mixed in with a regular serializer it will attempt to zlib
    compress the string to make it shorter if necessary. It will also
    base64 encode the string so that it can safely be placed in a URL.
    """
 
    default_serializer = _CompactJSON
 
    def load_payload(
        self,
        payload: bytes,
        *args: _t.Any,
        serializer: _t.Optional[_t.Any] = None,
        **kwargs: _t.Any,
    ) -> _t.Any:
        decompress = False
 
        if payload.startswith(b"."):
            payload = payload[1:]
            decompress = True
 
        try:
            json = base64_decode(payload)
        except Exception as e:
            raise BadPayload(
                "Could not base64 decode the payload because of an exception",
                original_error=e,
            ) from e
 
        if decompress:
            try:
                json = zlib.decompress(json)
            except Exception as e:
                raise BadPayload(
                    "Could not zlib decompress the payload before decoding the payload",
                    original_error=e,
                ) from e
 
        return super().load_payload(json, *args, **kwargs)
 
    def dump_payload(self, obj: _t.Any) -> bytes:
        json = super().dump_payload(obj)
        is_compressed = False
        compressed = zlib.compress(json)
 
        if len(compressed) < (len(json) - 1):
            json = compressed
            is_compressed = True
 
        base64d = base64_encode(json)
 
        if is_compressed:
            base64d = b"." + base64d
 
        return base64d
 
 
class URLSafeSerializer(URLSafeSerializerMixin, Serializer):
    """Works like :class:`.Serializer` but dumps and loads into a URL
    safe string consisting of the upper and lowercase character of the
    alphabet as well as ``'_'``, ``'-'`` and ``'.'``.
    """
 
 
class URLSafeTimedSerializer(URLSafeSerializerMixin, TimedSerializer):
    """Works like :class:`.TimedSerializer` but dumps and loads into a
    URL safe string consisting of the upper and lowercase character of
    the alphabet as well as ``'_'``, ``'-'`` and ``'.'``.
    """