From 2cc2fafd2e76b1f66cf2fa7ad93a5c4636eee6a8 Mon Sep 17 00:00:00 2001 From: Jesson Soto Ventura Date: Sun, 21 Jul 2019 12:59:23 -0400 Subject: [PATCH] Added console_flowlist_layout option - default - list - table --- mitmproxy/tools/console/common.py | 105 +++++++++++++++++++++-- mitmproxy/tools/console/consoleaddons.py | 14 +++ mitmproxy/tools/console/flowlist.py | 10 +++ mitmproxy/tools/console/flowview.py | 1 + mitmproxy/tools/console/palettes.py | 8 -- 5 files changed, 125 insertions(+), 13 deletions(-) diff --git a/mitmproxy/tools/console/common.py b/mitmproxy/tools/console/common.py index 58a83c0e4..ee2e2a76b 100644 --- a/mitmproxy/tools/console/common.py +++ b/mitmproxy/tools/console/common.py @@ -266,9 +266,95 @@ def colorize_url(url): ('url_punctuation', 3), # :// ] + colorize_host(parts[2]) + colorize_req('/' + parts[3]) +@lru_cache(maxsize=800) +def raw_format_list(f): + f = dict(f) + pile = [] + req = [] + if f["extended"]: + req.append( + fcol( + human.format_timestamp(f["req_timestamp"]), + "highlight" + ) + ) + else: + req.append(fcol(">>" if f["focus"] else " ", "focus")) + + if f["marked"]: + req.append(fcol(SYMBOL_MARK, "mark")) + + if f["req_is_replay"]: + req.append(fcol(SYMBOL_REPLAY, "replay")) + + req.append(fcol(f["req_method"], "method")) + + preamble = sum(i[1] for i in req) + len(req) - 1 + + if f["intercepted"] and not f["acked"]: + uc = "intercept" + elif "resp_code" in f or "err_msg" in f: + uc = "text" + else: + uc = "title" + + url = f["req_url"] + + if f["cols"] and len(url) > f["cols"]: + url = url[:f["cols"]] + "…" + + if f["req_http_version"] not in ("HTTP/1.0", "HTTP/1.1"): + url += " " + f["req_http_version"] + req.append( + urwid.Text([(uc, url)]) + ) + + pile.append(urwid.Columns(req, dividechars=1)) + + resp = [] + resp.append( + ("fixed", preamble, urwid.Text("")) + ) + + if "resp_code" in f: + codes = { + 2: "code_200", + 3: "code_300", + 4: "code_400", + 5: "code_500", + } + ccol = codes.get(f["resp_code"] // 100, "code_other") + resp.append(fcol(SYMBOL_RETURN, ccol)) + if f["resp_is_replay"]: + resp.append(fcol(SYMBOL_REPLAY, "replay")) + resp.append(fcol(f["resp_code"], ccol)) + if f["extended"]: + resp.append(fcol(f["resp_reason"], ccol)) + if f["intercepted"] and f["resp_code"] and not f["acked"]: + rc = "intercept" + else: + rc = "text" + + if f["resp_ctype"]: + resp.append(fcol(f["resp_ctype"], rc)) + resp.append(fcol(f["resp_clen"], rc)) + resp.append(fcol(f["duration"], rc)) + + elif f["err_msg"]: + resp.append(fcol(SYMBOL_RETURN, "error")) + resp.append( + urwid.Text([ + ( + "error", + f["err_msg"] + ) + ]) + ) + pile.append(urwid.Columns(resp, dividechars=1)) + return urwid.Pile(pile) @lru_cache(maxsize=800) -def raw_format_flow(f): +def raw_format_table(f): f = dict(f) pile = [] req = [] @@ -415,14 +501,15 @@ def raw_format_flow(f): return urwid.Pile(pile) -def format_flow(f, focus, extended=False, hostheader=False, cols=False): +def format_flow(f, focus, extended=False, hostheader=False, cols=False, layout='default'): acked = False if f.reply and f.reply.state == "committed": acked = True d = dict( focus=focus, extended=extended, - two_line=extended or cols < 100, + two_line=extended or cols < 80, + cols=cols, intercepted=f.intercepted, acked=acked, req_timestamp=f.request.timestamp_start, @@ -440,10 +527,14 @@ def format_flow(f, focus, extended=False, hostheader=False, cols=False): if f.response: if f.response.raw_content: content_len = len(f.response.raw_content) + contentdesc = human.pretty_size(len(f.response.raw_content)) elif f.response.raw_content is None: content_len = -1 + contentdesc = "[content missing]" else: content_len = -2 + contentdesc = "[no content]" + duration = None if f.response.timestamp_end and f.request.timestamp_start: duration = f.response.timestamp_end - f.request.timestamp_start @@ -454,7 +545,11 @@ def format_flow(f, focus, extended=False, hostheader=False, cols=False): resp_is_replay=f.response.is_replay, resp_len=content_len, resp_ctype=f.response.headers.get("content-type"), + resp_clen=contentdesc, duration=duration, - )) + )) - return raw_format_flow(tuple(sorted(d.items()))) + if ( (layout == 'default' and cols < 80) or layout == "list"): + return raw_format_list(tuple(sorted(d.items()))) + else: + return raw_format_table(tuple(sorted(d.items()))) diff --git a/mitmproxy/tools/console/consoleaddons.py b/mitmproxy/tools/console/consoleaddons.py index a40cdeaa7..0f7383f66 100644 --- a/mitmproxy/tools/console/consoleaddons.py +++ b/mitmproxy/tools/console/consoleaddons.py @@ -37,6 +37,12 @@ console_layouts = [ "horizontal", ] +console_flowlist_layout = [ + "default", + "table", + "list" +] + class UnsupportedLog: """ @@ -114,6 +120,14 @@ class ConsoleAddon: "Console mouse interaction." ) + loader.add_option( + "console_flowlist_layout", + str, "default", + "Set the flowlist layout", + choices=sorted(console_flowlist_layout) + + ) + @command.command("console.layout.options") def layout_options(self) -> typing.Sequence[str]: """ diff --git a/mitmproxy/tools/console/flowlist.py b/mitmproxy/tools/console/flowlist.py index 63e673270..64c5e10c7 100644 --- a/mitmproxy/tools/console/flowlist.py +++ b/mitmproxy/tools/console/flowlist.py @@ -19,6 +19,7 @@ class FlowItem(urwid.WidgetWrap): self.flow is self.master.view.focus.flow, hostheader=self.master.options.showhost, cols=cols, + layout=self.master.options.console_flowlist_layout ) def selectable(self): @@ -84,6 +85,11 @@ class FlowListBox(urwid.ListBox, layoutwidget.LayoutWidget): ) -> None: self.master: "mitmproxy.tools.console.master.ConsoleMaster" = master super().__init__(FlowListWalker(master)) + self.master.options.subscribe( + self.set_flowlist_layout, + ["console_flowlist_layout"] + ) + def keypress(self, size, key): if key == "m_start": @@ -96,3 +102,7 @@ class FlowListBox(urwid.ListBox, layoutwidget.LayoutWidget): def view_changed(self): self.body.view_changed() + + def set_flowlist_layout(self, opts, updated): + self.master.ui.clear() + diff --git a/mitmproxy/tools/console/flowview.py b/mitmproxy/tools/console/flowview.py index 5466319ab..807c97140 100644 --- a/mitmproxy/tools/console/flowview.py +++ b/mitmproxy/tools/console/flowview.py @@ -39,6 +39,7 @@ class FlowViewHeader(urwid.WidgetWrap): extended=True, hostheader=self.master.options.showhost, cols=cols, + layout=self.master.options.console_flowlist_layout ) else: self._w = urwid.Pile([]) diff --git a/mitmproxy/tools/console/palettes.py b/mitmproxy/tools/console/palettes.py index a96689bf4..2a7f12545 100644 --- a/mitmproxy/tools/console/palettes.py +++ b/mitmproxy/tools/console/palettes.py @@ -425,14 +425,6 @@ class SolarizedDark(LowDark): method_other = (sol_magenta, 'default'), method_http2_push = (sol_base01, 'default'), - method = (sol_cyan, 'default'), - method_get = (sol_green, 'default'), - method_post = (sol_orange, 'default'), - method_delete = (sol_red, 'default'), - method_head = (sol_cyan, 'default'), - method_put = (sol_red, 'default'), - method_other = (sol_magenta, 'default'), - url_punctuation = ('h242', 'default'), url_domain = ('h252', 'default'), url_filename = ('h132', 'default'),