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
|
import re
import json
import typing
from mitmproxy.contentviews import base
PARSE_ERROR = object()
def parse_json(s: bytes) -> typing.Any:
try:
return json.loads(s.decode('utf-8'))
except ValueError:
return PARSE_ERROR
def format_json(data: typing.Any) -> typing.Iterator[base.TViewLine]:
encoder = json.JSONEncoder(indent=4, sort_keys=True, ensure_ascii=False)
current_line: base.TViewLine = []
for chunk in encoder.iterencode(data):
if "\n" in chunk:
rest_of_last_line, chunk = chunk.split("\n", maxsplit=1)
# rest_of_last_line is a delimiter such as , or [
current_line.append(('text', rest_of_last_line))
yield current_line
current_line = []
if re.match(r'\s*"', chunk):
current_line.append(('json_string', chunk))
elif re.match(r'\s*\d', chunk):
current_line.append(('json_number', chunk))
elif re.match(r'\s*(true|null|false)', chunk):
current_line.append(('json_boolean', chunk))
else:
current_line.append(('text', chunk))
yield current_line
class ViewJSON(base.View):
name = "JSON"
content_types = [
"application/json",
"application/json-rpc",
"application/vnd.api+json"
]
def __call__(self, data, **metadata):
data = parse_json(data)
if data is not PARSE_ERROR:
return "JSON", format_json(data)
|