aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMaximilian Hils <git@maximilianhils.com>2020-04-19 17:44:17 +0200
committerGitHub <noreply@github.com>2020-04-19 17:44:17 +0200
commit3c1a184c5d440e08726d758ba4693f4a51e50433 (patch)
treefa2297f519df360922760d7068ca0e0e15505980
parent2774928319b706d8b6f85919f8811776342986c9 (diff)
parentca74ec3c774345bccc0e4e90fe6c231ce598663c (diff)
downloadmitmproxy-3c1a184c5d440e08726d758ba4693f4a51e50433.tar.gz
mitmproxy-3c1a184c5d440e08726d758ba4693f4a51e50433.tar.bz2
mitmproxy-3c1a184c5d440e08726d758ba4693f4a51e50433.zip
Merge pull request #3929 from sarthak212/colorizejson
colorize json
-rw-r--r--mitmproxy/contentviews/json.py41
-rw-r--r--mitmproxy/tools/console/palettes.py23
-rw-r--r--test/mitmproxy/contentviews/test_json.py37
3 files changed, 87 insertions, 14 deletions
diff --git a/mitmproxy/contentviews/json.py b/mitmproxy/contentviews/json.py
index 15c624ad..a5a7d03b 100644
--- a/mitmproxy/contentviews/json.py
+++ b/mitmproxy/contentviews/json.py
@@ -1,16 +1,39 @@
+import re
import json
-from typing import Optional
+
+import typing
from mitmproxy.contentviews import base
+PARSE_ERROR = object()
+
-def pretty_json(s: bytes) -> Optional[bytes]:
+def parse_json(s: bytes) -> typing.Any:
try:
- p = json.loads(s.decode('utf-8'))
+ return json.loads(s.decode('utf-8'))
except ValueError:
- return None
- pretty = json.dumps(p, sort_keys=True, indent=4, ensure_ascii=False)
- return pretty.encode("utf8", "strict")
+ 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):
@@ -22,6 +45,6 @@ class ViewJSON(base.View):
]
def __call__(self, data, **metadata):
- pj = pretty_json(data)
- if pj:
- return "JSON", base.format_text(pj)
+ data = parse_json(data)
+ if data is not PARSE_ERROR:
+ return "JSON", format_json(data)
diff --git a/mitmproxy/tools/console/palettes.py b/mitmproxy/tools/console/palettes.py
index 0a1dd8df..a680a5a7 100644
--- a/mitmproxy/tools/console/palettes.py
+++ b/mitmproxy/tools/console/palettes.py
@@ -34,6 +34,9 @@ class Palette:
# Hex view
'offset',
+ # JSON view
+ 'json_string', 'json_number', 'json_boolean',
+
# Grid Editor
'focusfield', 'focusfield_error', 'field_error', 'editfield',
@@ -169,6 +172,11 @@ class LowDark(Palette):
# Hex view
offset = ('dark cyan', 'default'),
+ # JSON view
+ json_string = ('dark blue', 'default'),
+ json_number = ('light magenta', 'default'),
+ json_boolean = ('dark magenta', 'default'),
+
# Grid Editor
focusfield = ('black', 'light gray'),
focusfield_error = ('dark red', 'light gray'),
@@ -269,6 +277,11 @@ class LowLight(Palette):
# Hex view
offset = ('dark blue', 'default'),
+ # JSON view
+ json_string = ('dark blue', 'default'),
+ json_number = ('light magenta', 'default'),
+ json_boolean = ('dark magenta', 'default'),
+
# Grid Editor
focusfield = ('black', 'light gray'),
focusfield_error = ('dark red', 'light gray'),
@@ -379,6 +392,11 @@ class SolarizedLight(LowLight):
# Hex view
offset = (sol_cyan, 'default'),
+ # JSON view
+ json_string = (sol_cyan, 'default'),
+ json_number = (sol_blue, 'default'),
+ json_boolean = (sol_magenta, 'default'),
+
# Grid Editor
focusfield = (sol_base00, sol_base2),
focusfield_error = (sol_red, sol_base2),
@@ -452,6 +470,11 @@ class SolarizedDark(LowDark):
# Hex view
offset = (sol_cyan, 'default'),
+ # JSON view
+ json_string = (sol_cyan, 'default'),
+ json_number = (sol_blue, 'default'),
+ json_boolean = (sol_magenta, 'default'),
+
# Grid Editor
focusfield = (sol_base0, sol_base02),
focusfield_error = (sol_red, sol_base02),
diff --git a/test/mitmproxy/contentviews/test_json.py b/test/mitmproxy/contentviews/test_json.py
index 5e87b570..2b5bf86a 100644
--- a/test/mitmproxy/contentviews/test_json.py
+++ b/test/mitmproxy/contentviews/test_json.py
@@ -1,16 +1,43 @@
+from hypothesis import given
+from hypothesis.strategies import binary
+
from mitmproxy.contentviews import json
from . import full_eval
-def test_pretty_json():
- assert json.pretty_json(b'{"foo": 1}')
- assert not json.pretty_json(b"moo")
- assert json.pretty_json(b'{"foo" : "\xe4\xb8\x96\xe7\x95\x8c"}') # utf8 with chinese characters
- assert not json.pretty_json(b'{"foo" : "\xFF"}')
+def test_parse_json():
+ assert json.parse_json(b'{"foo": 1}')
+ assert json.parse_json(b'null') is None
+ assert json.parse_json(b"moo") is json.PARSE_ERROR
+ assert json.parse_json(b'{"foo" : "\xe4\xb8\x96\xe7\x95\x8c"}') # utf8 with chinese characters
+ assert json.parse_json(b'{"foo" : "\xFF"}') is json.PARSE_ERROR
+
+
+def test_format_json():
+ assert list(json.format_json({
+ "data": [
+ "str",
+ 42,
+ True,
+ False,
+ None,
+ {},
+ []
+ ]
+ }))
def test_view_json():
v = full_eval(json.ViewJSON())
+ assert v(b"null")
assert v(b"{}")
assert not v(b"{")
assert v(b"[1, 2, 3, 4, 5]")
+ assert v(b'{"foo" : 3}')
+ assert v(b'{"foo": true, "nullvalue": null}')
+
+
+@given(binary())
+def test_view_json_doesnt_crash(data):
+ v = full_eval(json.ViewJSON())
+ v(data)