From 8f5cf833d08aba685263554d0bd89f922cd6afae Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Sun, 29 Mar 2015 19:21:54 +1300 Subject: Add flow detail view as a tab in the flow view --- libmproxy/console/__init__.py | 9 -- libmproxy/console/flowdetailview.py | 176 +++++++++++++++++------------------- libmproxy/console/flowview.py | 11 ++- libmproxy/console/searchable.py | 2 +- libmproxy/console/tabs.py | 8 +- 5 files changed, 95 insertions(+), 111 deletions(-) diff --git a/libmproxy/console/__init__.py b/libmproxy/console/__init__.py index 35126eba..6e9d227b 100644 --- a/libmproxy/console/__init__.py +++ b/libmproxy/console/__init__.py @@ -453,15 +453,6 @@ class ConsoleMaster(flow.FlowMaster): statusbar.StatusBar(self, help.footer) ) - def view_flowdetails(self, flow): - signals.push_view_state.send(self) - self.loop.widget = window.Window( - self, - flowdetailview.FlowDetailsView(flow), - None, - statusbar.StatusBar(self, flowdetailview.footer) - ) - def view_grideditor(self, ge): signals.push_view_state.send(self) self.help_context = ge.make_help() diff --git a/libmproxy/console/flowdetailview.py b/libmproxy/console/flowdetailview.py index 8bfdae4a..99f2a262 100644 --- a/libmproxy/console/flowdetailview.py +++ b/libmproxy/console/flowdetailview.py @@ -1,110 +1,100 @@ from __future__ import absolute_import import urwid -from . import common, signals +from . import common, signals, searchable from .. import utils -footer = [ - ('heading_key', "q"), ":back ", -] +def flowdetails(state, flow): + text = [] -class FlowDetailsView(urwid.ListBox): - def __init__(self, flow): - self.flow = flow - urwid.ListBox.__init__( - self, - self.flowtext() - ) - - def keypress(self, size, key): - key = common.shortcuts(key) - if key == "q": - signals.pop_view_state.send(self) - return None - elif key == "?": - key = None - return urwid.ListBox.keypress(self, size, key) - - def flowtext(self): - text = [] + cc = flow.client_conn + sc = flow.server_conn + req = flow.request + resp = flow.response - title = urwid.Text("Flow details") - title = urwid.Padding(title, align="left", width=("relative", 100)) - title = urwid.AttrWrap(title, "heading") - text.append(title) + if sc: + text.append(urwid.Text([("head", "Server Connection:")])) + parts = [ + ["Address", "%s:%s" % sc.address()], + ] - cc = self.flow.client_conn - sc = self.flow.server_conn - req = self.flow.request - resp = self.flow.response + text.extend( + common.format_keyvals(parts, key="key", val="text", indent=4) + ) - if sc: - text.append(urwid.Text([("head", "Server Connection:")])) + c = sc.cert + if c: + text.append(urwid.Text([("head", "Server Certificate:")])) parts = [ - ["Address", "%s:%s" % sc.address()], + ["Type", "%s, %s bits"%c.keyinfo], + ["SHA1 digest", c.digest("sha1")], + ["Valid to", str(c.notafter)], + ["Valid from", str(c.notbefore)], + ["Serial", str(c.serial)], + [ + "Subject", + urwid.BoxAdapter( + urwid.ListBox( + common.format_keyvals( + c.subject, + key="highlight", + val="text" + ) + ), + len(c.subject) + ) + ], + [ + "Issuer", + urwid.BoxAdapter( + urwid.ListBox( + common.format_keyvals( + c.issuer, key="highlight", val="text" + ) + ), + len(c.issuer) + ) + ] ] - text.extend(common.format_keyvals(parts, key="key", val="text", indent=4)) - - c = sc.cert - if c: - text.append(urwid.Text([("head", "Server Certificate:")])) - parts = [ - ["Type", "%s, %s bits"%c.keyinfo], - ["SHA1 digest", c.digest("sha1")], - ["Valid to", str(c.notafter)], - ["Valid from", str(c.notbefore)], - ["Serial", str(c.serial)], - [ - "Subject", - urwid.BoxAdapter( - urwid.ListBox(common.format_keyvals(c.subject, key="highlight", val="text")), - len(c.subject) - ) - ], + if c.altnames: + parts.append( [ - "Issuer", - urwid.BoxAdapter( - urwid.ListBox(common.format_keyvals(c.issuer, key="highlight", val="text")), - len(c.issuer) - ) + "Alt names", + ", ".join(c.altnames) ] - ] - - if c.altnames: - parts.append( - [ - "Alt names", - ", ".join(c.altnames) - ] - ) - text.extend(common.format_keyvals(parts, key="key", val="text", indent=4)) + ) + text.extend( + common.format_keyvals(parts, key="key", val="text", indent=4) + ) - if cc: - text.append(urwid.Text([("head", "Client Connection:")])) + if cc: + text.append(urwid.Text([("head", "Client Connection:")])) - parts = [ - ["Address", "%s:%s" % cc.address()], - # ["Requests", "%s"%cc.requestcount], - ] + parts = [ + ["Address", "%s:%s" % cc.address()], + # ["Requests", "%s"%cc.requestcount], + ] - text.extend(common.format_keyvals(parts, key="key", val="text", indent=4)) - - parts = [] - - parts.append(["Client conn. established", utils.format_timestamp_with_milli(cc.timestamp_start) if (cc and cc.timestamp_start) else "active"]) - parts.append(["Server conn. initiated", utils.format_timestamp_with_milli(sc.timestamp_start) if sc else "active" ]) - parts.append(["Server conn. TCP handshake", utils.format_timestamp_with_milli(sc.timestamp_tcp_setup) if (sc and sc.timestamp_tcp_setup) else "active"]) - if sc.ssl_established: - parts.append(["Server conn. SSL handshake", utils.format_timestamp_with_milli(sc.timestamp_ssl_setup) if sc.timestamp_ssl_setup else "active"]) - parts.append(["Client conn. SSL handshake", utils.format_timestamp_with_milli(cc.timestamp_ssl_setup) if (cc and cc.timestamp_ssl_setup) else "active"]) - parts.append(["First request byte", utils.format_timestamp_with_milli(req.timestamp_start)]) - parts.append(["Request complete", utils.format_timestamp_with_milli(req.timestamp_end) if req.timestamp_end else "active"]) - parts.append(["First response byte", utils.format_timestamp_with_milli(resp.timestamp_start) if resp else "active"]) - parts.append(["Response complete", utils.format_timestamp_with_milli(resp.timestamp_end) if (resp and resp.timestamp_end) else "active"]) - - # sort operations by timestamp - parts = sorted(parts, key=lambda p: p[1]) + text.extend( + common.format_keyvals(parts, key="key", val="text", indent=4) + ) - text.append(urwid.Text([("head", "Timing:")])) - text.extend(common.format_keyvals(parts, key="key", val="text", indent=4)) - return text + parts = [] + + parts.append(["Client conn. established", utils.format_timestamp_with_milli(cc.timestamp_start) if (cc and cc.timestamp_start) else "active"]) + parts.append(["Server conn. initiated", utils.format_timestamp_with_milli(sc.timestamp_start) if sc else "active" ]) + parts.append(["Server conn. TCP handshake", utils.format_timestamp_with_milli(sc.timestamp_tcp_setup) if (sc and sc.timestamp_tcp_setup) else "active"]) + if sc.ssl_established: + parts.append(["Server conn. SSL handshake", utils.format_timestamp_with_milli(sc.timestamp_ssl_setup) if sc.timestamp_ssl_setup else "active"]) + parts.append(["Client conn. SSL handshake", utils.format_timestamp_with_milli(cc.timestamp_ssl_setup) if (cc and cc.timestamp_ssl_setup) else "active"]) + parts.append(["First request byte", utils.format_timestamp_with_milli(req.timestamp_start)]) + parts.append(["Request complete", utils.format_timestamp_with_milli(req.timestamp_end) if req.timestamp_end else "active"]) + parts.append(["First response byte", utils.format_timestamp_with_milli(resp.timestamp_start) if resp else "active"]) + parts.append(["Response complete", utils.format_timestamp_with_milli(resp.timestamp_end) if (resp and resp.timestamp_end) else "active"]) + + # sort operations by timestamp + parts = sorted(parts, key=lambda p: p[1]) + + text.append(urwid.Text([("head", "Timing:")])) + text.extend(common.format_keyvals(parts, key="key", val="text", indent=4)) + return searchable.Searchable(state, text) diff --git a/libmproxy/console/flowview.py b/libmproxy/console/flowview.py index ffe499d7..514340c9 100644 --- a/libmproxy/console/flowview.py +++ b/libmproxy/console/flowview.py @@ -2,6 +2,7 @@ from __future__ import absolute_import import os, sys, copy import urwid from . import common, grideditor, contentview, signals, searchable, tabs +from . import flowdetailview from .. import utils, flow, controller from ..protocol.http import HTTPRequest, HTTPResponse, CONTENT_MISSING, decoded @@ -65,7 +66,6 @@ def _mkhelp(): ("w", "save all flows matching current limit"), ("W", "save this flow"), ("x", "delete body"), - ("X", "view flow details"), ("z", "encode/decode a request/response"), ("tab", "toggle request/response view"), ("space", "next flow"), @@ -121,6 +121,7 @@ class FlowView(tabs.Tabs): [ (self.tab_request, self.view_request), (self.tab_response, self.view_response), + (self.tab_details, self.view_details), ], tab_offset ) @@ -140,13 +141,17 @@ class FlowView(tabs.Tabs): else: return "Response" + def tab_details(self): + return "Detail" + def view_request(self): return self.conn_text(self.flow.request) def view_response(self): return self.conn_text(self.flow.response) - + def view_details(self): + return flowdetailview.flowdetails(self.state, self.flow) def sig_flow_change(self, sender, flow): if flow == self.flow: @@ -568,8 +573,6 @@ class FlowView(tabs.Tabs): callback = self.delete_body ) key = None - elif key == "X": - self.master.view_flowdetails(self.flow) elif key == "z": if conn: self.flow.backup() diff --git a/libmproxy/console/searchable.py b/libmproxy/console/searchable.py index 8f63c3f5..9d66c718 100644 --- a/libmproxy/console/searchable.py +++ b/libmproxy/console/searchable.py @@ -36,7 +36,7 @@ class Searchable(urwid.ListBox): if key == "N": self.find_next(True) else: - return super(self.__class__, self).keypress(size, key) + return key def set_search(self, text): self.state.last_search = text diff --git a/libmproxy/console/tabs.py b/libmproxy/console/tabs.py index 3245f430..b8943ad4 100644 --- a/libmproxy/console/tabs.py +++ b/libmproxy/console/tabs.py @@ -8,8 +8,8 @@ class Tabs(urwid.WidgetWrap): self.show() def _tab(self, content, attr): - p = urwid.Text(content) - p = urwid.Padding(p, align="left", width=("relative", 100)) + p = urwid.Text(content, align="center") + p = urwid.Padding(p, align="center", width=("relative", 100)) p = urwid.AttrWrap(p, attr) return p @@ -18,7 +18,7 @@ class Tabs(urwid.WidgetWrap): self.tab_offset = (self.tab_offset + 1)%(len(self.tabs)) self.show() else: - return key + return self._w.keypress(size, key) def show(self): headers = [] @@ -28,7 +28,7 @@ class Tabs(urwid.WidgetWrap): headers.append(self._tab(txt, "heading")) else: headers.append(self._tab(txt, "heading_inactive")) - headers = urwid.Columns(headers) + headers = urwid.Columns(headers, dividechars=1) self._w = urwid.Frame( body = self.tabs[self.tab_offset][1](), header = headers -- cgit v1.2.3