From 18d4c3a9e96fad9683b87e2202a078722291a72b Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Thu, 30 Jun 2011 13:27:27 +1200 Subject: JSON pretty-printing. Also rename the display modes ("pretty" instead of "indent"), and expand the built-in documentation. --- libmproxy/console.py | 70 +++++++++++++++++++++++++++++++++------------------- libmproxy/utils.py | 9 +++++++ 2 files changed, 54 insertions(+), 25 deletions(-) (limited to 'libmproxy') diff --git a/libmproxy/console.py b/libmproxy/console.py index d1e27be6..4ae1f23a 100644 --- a/libmproxy/console.py +++ b/libmproxy/console.py @@ -224,7 +224,7 @@ class ConnectionViewHeader(WWrap): VIEW_BODY_RAW = 0 VIEW_BODY_BINARY = 1 -VIEW_BODY_INDENT = 2 +VIEW_BODY_PRETTY = 2 VIEW_FLOW_REQUEST = 0 VIEW_FLOW_RESPONSE = 1 @@ -418,8 +418,8 @@ class ConnectionView(WWrap): self.state.view_body_mode = VIEW_BODY_RAW elif v == "h": self.state.view_body_mode = VIEW_BODY_BINARY - elif v == "i": - self.state.view_body_mode = VIEW_BODY_INDENT + elif v == "p": + self.state.view_body_mode = VIEW_BODY_PRETTY self.master.refresh_connection(self.flow) def keypress(self, size, key): @@ -442,7 +442,7 @@ class ConnectionView(WWrap): "View", ( ("raw", "r"), - ("indent", "i"), + ("pretty", "p"), ("hex", "h"), ), self._changeview @@ -881,8 +881,8 @@ class ConsoleMaster(flow.FlowMaster): self.spawn_external_viewer(serr, None) self.refresh_connection(f) - def _trailer(self, content, txt): - rem = len(content) - VIEW_CUTOFF + def _trailer(self, clen, txt): + rem = clen - VIEW_CUTOFF if rem > 0: txt.append(urwid.Text("")) txt.append( @@ -893,12 +893,12 @@ class ConsoleMaster(flow.FlowMaster): ) ) - def _view_conn_normal(self, content, txt): - for i in content[:VIEW_CUTOFF].splitlines(): + def _view_conn_raw(self, content, txt): + for i in utils.cleanBin(content[:VIEW_CUTOFF]).splitlines(): txt.append( urwid.Text(("text", i)) ) - self._trailer(content, txt) + self._trailer(len(content), txt) def _view_conn_binary(self, content, txt): for offset, hex, s in utils.hexdump(content[:VIEW_CUTOFF]): @@ -909,14 +909,40 @@ class ConsoleMaster(flow.FlowMaster): " ", ("text", s), ])) - self._trailer(content, txt) + self._trailer(len(content), txt) - def _view_conn_pretty(self, content, txt): + def _view_conn_xmlish(self, content, txt): for i in utils.pretty_xmlish(content[:VIEW_CUTOFF]): txt.append( urwid.Text(("text", i)), ) - self._trailer(content, txt) + self._trailer(len(content), txt) + + def _view_conn_json(self, lines, txt): + sofar = 0 + for i in lines: + sofar += len(i) + txt.append( + urwid.Text(("text", i)), + ) + if sofar > VIEW_CUTOFF: + break + self._trailer(sum(len(i) for i in lines), txt) + + + def _find_pretty_view(self, content, hdrItems, txt): + ctype = None + for i in hdrItems: + if i[0] == "content-type": + ctype = i[1] + break + if utils.isXML(content): + return self._view_conn_xmlish(content, txt) + if ctype and "application/json" in ctype: + lines = utils.pretty_json(content) + if lines: + return self._view_conn_json(lines, txt) + return self._view_conn_raw(content, txt) @utils.LRUCache(20) def _cached_conn_text(self, content, hdrItems, viewmode): @@ -934,19 +960,10 @@ class ConsoleMaster(flow.FlowMaster): if content: if viewmode == VIEW_BODY_BINARY: self._view_conn_binary(content, txt) - elif viewmode == VIEW_BODY_INDENT: - if utils.isXML(content): - self._view_conn_pretty(content, txt) - else: - if utils.isBin(content): - self._view_conn_binary(content, txt) - else: - self._view_conn_normal(content, txt) + elif viewmode == VIEW_BODY_PRETTY: + self._find_pretty_view(content, hdrItems, txt) else: - if utils.isBin(content): - self._view_conn_binary(content, txt) - else: - self._view_conn_normal(content, txt) + self._view_conn_raw(content, txt) return urwid.ListBox(txt) def _readflow(self, path): @@ -1206,7 +1223,10 @@ class ConsoleMaster(flow.FlowMaster): keys = [ ("b", "save request/response body"), ("e", "edit request/response"), - ("m", "change view mode (raw, indent, hex)"), + ("m", "change view mode (raw, pretty, hex)"), + (None, " raw: raw data"), + (None, " pretty: pretty-print XML, HTML and JSON"), + (None, " hex: hex dump"), ("p", "previous flow"), ("v", "view body in external viewer"), ("|", "run script"), diff --git a/libmproxy/utils.py b/libmproxy/utils.py index b5dc6d92..8ac1f547 100644 --- a/libmproxy/utils.py +++ b/libmproxy/utils.py @@ -13,6 +13,7 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . import re, os, subprocess, datetime, textwrap, errno, sys, time, functools +import json CERT_SLEEP_TIME = 1 @@ -111,6 +112,14 @@ def pretty_xmlish(s): return data +def pretty_json(s): + try: + p = json.loads(s) + except ValueError: + return None + return json.dumps(p, sort_keys=True, indent=4).split("\n") + + def hexdump(s): """ Returns a set of typles: -- cgit v1.2.3