aboutsummaryrefslogtreecommitdiffstats
path: root/mitmproxy/contentviews/base.py
blob: 81f2e4879ca4319eab3963fcbbadddc1eee6f1de (plain)
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
81
82
83
84
85
86
87
88
89
# Default view cutoff *in lines*
import typing

KEY_MAX = 30

TTextType = typing.Union[str, bytes]  # FIXME: This should be either bytes or str ultimately.
TViewLine = typing.List[typing.Tuple[str, TTextType]]
TViewResult = typing.Tuple[str, typing.Iterator[TViewLine]]


class View:
    name: typing.ClassVar[str]
    content_types: typing.ClassVar[typing.List[str]] = []

    def __call__(self, data: bytes, **metadata) -> TViewResult:
        """
        Transform raw data into human-readable output.

        Args:
            data: the data to decode/format.
            metadata: optional keyword-only arguments for metadata. Implementations must not
                rely on a given argument being present.

        Returns:
            A (description, content generator) tuple.

            The content generator yields lists of (style, text) tuples, where each list represents
            a single line. ``text`` is a unfiltered byte string which may need to be escaped,
            depending on the used output.

        Caveats:
            The content generator must not yield tuples of tuples,
            because urwid cannot process that. You have to yield a *list* of tuples per line.
        """
        raise NotImplementedError()  # pragma: no cover


def format_pairs(
        items: typing.Iterable[typing.Tuple[TTextType, TTextType]]
) -> typing.Iterator[TViewLine]:

    """
    Helper function that accepts a list of (k,v) pairs into a list of
    [
        ("key", key    )
        ("value", value)
    ]
    where key is padded to a uniform width
    """

    max_key_len = max((len(k[0]) for k in items), default=0)
    max_key_len = min((max_key_len, KEY_MAX), default=0)

    for key, value in items:
        if isinstance(key, bytes):

            key += b":"
        else:
            key += ":"

        key = key.ljust(max_key_len + 2)

        yield [
            ("header", key),
            ("text", value)
        ]


def format_dict(
        d: typing.Mapping[TTextType, TTextType]
) -> typing.Iterator[TViewLine]:
    """
    Helper function that transforms the given dictionary into a list of
    [
        ("key",   key  )
        ("value", value)
    ]
    entries, where key is padded to a uniform width.
    """

    return format_pairs(d.items())


def format_text(text: TTextType) -> typing.Iterator[TViewLine]:
    """
    Helper function that transforms bytes into the view output format.
    """
    for line in text.splitlines():
        yield [("text", line)]