aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMaximilian Hils <git@maximilianhils.com>2020-04-12 00:55:04 +0200
committerMaximilian Hils <git@maximilianhils.com>2020-04-12 00:55:04 +0200
commitd1cb0dbec5dc430d5293719bac11749c79699e24 (patch)
tree4c9b5a5618dc8949257d0ee64bdabc156bbdd945
parentd33857588cc8351da17fed9ea2486b8b193bd8b8 (diff)
downloadmitmproxy-d1cb0dbec5dc430d5293719bac11749c79699e24.tar.gz
mitmproxy-d1cb0dbec5dc430d5293719bac11749c79699e24.tar.bz2
mitmproxy-d1cb0dbec5dc430d5293719bac11749c79699e24.zip
add very simply tcp detailview
-rw-r--r--mitmproxy/addons/clientplayback.py13
-rw-r--r--mitmproxy/tools/console/consoleaddons.py6
-rw-r--r--mitmproxy/tools/console/flowdetailview.py23
-rw-r--r--mitmproxy/tools/console/flowlist.py5
-rw-r--r--mitmproxy/tools/console/flowview.py89
5 files changed, 102 insertions, 34 deletions
diff --git a/mitmproxy/addons/clientplayback.py b/mitmproxy/addons/clientplayback.py
index 7adefd7a..6a3cc5fb 100644
--- a/mitmproxy/addons/clientplayback.py
+++ b/mitmproxy/addons/clientplayback.py
@@ -127,15 +127,18 @@ class ClientPlayback:
self.q = queue.Queue()
self.thread: RequestReplayThread = None
- def check(self, f: http.HTTPFlow):
+ def check(self, f: flow.Flow):
if f.live:
return "Can't replay live flow."
if f.intercepted:
return "Can't replay intercepted flow."
- if not f.request:
- return "Can't replay flow with missing request."
- if f.request.raw_content is None:
- return "Can't replay flow with missing content."
+ if isinstance(f, http.HTTPFlow):
+ if not f.request:
+ return "Can't replay flow with missing request."
+ if f.request.raw_content is None:
+ return "Can't replay flow with missing content."
+ else:
+ return "Can only replay HTTP flows."
def load(self, loader):
loader.add_option(
diff --git a/mitmproxy/tools/console/consoleaddons.py b/mitmproxy/tools/console/consoleaddons.py
index 129d889f..12448945 100644
--- a/mitmproxy/tools/console/consoleaddons.py
+++ b/mitmproxy/tools/console/consoleaddons.py
@@ -9,6 +9,7 @@ from mitmproxy import exceptions
from mitmproxy import flow
from mitmproxy import http
from mitmproxy import log
+from mitmproxy import tcp
from mitmproxy.tools.console import keymap
from mitmproxy.tools.console import overlay
from mitmproxy.tools.console import signals
@@ -334,9 +335,10 @@ class ConsoleAddon:
@command.command("console.view.flow")
def view_flow(self, flow: flow.Flow) -> None:
"""View a flow."""
- if hasattr(flow, "request"):
- # FIME: Also set focus?
+ if isinstance(flow, (http.HTTPFlow, tcp.TCPFlow)):
self.master.switch_view("flowview")
+ else:
+ ctx.log.warn(f"No detail view for {type(flow).__name__}.")
@command.command("console.exit")
def exit(self) -> None:
diff --git a/mitmproxy/tools/console/flowdetailview.py b/mitmproxy/tools/console/flowdetailview.py
index 443ca526..ec716936 100644
--- a/mitmproxy/tools/console/flowdetailview.py
+++ b/mitmproxy/tools/console/flowdetailview.py
@@ -1,5 +1,6 @@
import urwid
+import mitmproxy.flow
from mitmproxy import http
from mitmproxy.tools.console import common, searchable
from mitmproxy.utils import human
@@ -13,13 +14,17 @@ def maybe_timestamp(base, attr):
return "active"
-def flowdetails(state, flow: http.HTTPFlow):
+def flowdetails(state, flow: mitmproxy.flow.Flow):
text = []
sc = flow.server_conn
cc = flow.client_conn
- req = flow.request
- resp = flow.response
+ if isinstance(flow, http.HTTPFlow):
+ req = flow.request
+ resp = flow.response
+ else:
+ req = None
+ resp = None
metadata = flow.metadata
if metadata is not None and len(metadata) > 0:
@@ -126,6 +131,12 @@ def flowdetails(state, flow: http.HTTPFlow):
maybe_timestamp(cc, "timestamp_tls_setup")
)
)
+ parts.append(
+ (
+ "Client conn. closed",
+ maybe_timestamp(cc, "timestamp_end")
+ )
+ )
if sc is not None and sc.timestamp_start:
parts.append(
@@ -147,6 +158,12 @@ def flowdetails(state, flow: http.HTTPFlow):
maybe_timestamp(sc, "timestamp_tls_setup")
)
)
+ parts.append(
+ (
+ "Server conn. closed",
+ maybe_timestamp(sc, "timestamp_end")
+ )
+ )
if req is not None and req.timestamp_start:
parts.append(
diff --git a/mitmproxy/tools/console/flowlist.py b/mitmproxy/tools/console/flowlist.py
index 24d4c96b..b21a16b3 100644
--- a/mitmproxy/tools/console/flowlist.py
+++ b/mitmproxy/tools/console/flowlist.py
@@ -32,9 +32,8 @@ class FlowItem(urwid.WidgetWrap):
def mouse_event(self, size, event, button, col, row, focus):
if event == "mouse press" and button == 1:
- if self.flow.request:
- self.master.commands.execute("console.view.flow @focus")
- return True
+ self.master.commands.execute("console.view.flow @focus")
+ return True
def keypress(self, size, key):
return key
diff --git a/mitmproxy/tools/console/flowview.py b/mitmproxy/tools/console/flowview.py
index 60321e46..c4dafee6 100644
--- a/mitmproxy/tools/console/flowview.py
+++ b/mitmproxy/tools/console/flowview.py
@@ -5,9 +5,11 @@ from typing import Optional, Union # noqa
import urwid
+import mitmproxy.flow
from mitmproxy import contentviews
from mitmproxy import ctx
from mitmproxy import http
+from mitmproxy import tcp
from mitmproxy.tools.console import common
from mitmproxy.tools.console import layoutwidget
from mitmproxy.tools.console import flowdetailview
@@ -24,8 +26,8 @@ class SearchError(Exception):
class FlowViewHeader(urwid.WidgetWrap):
def __init__(
- self,
- master: "mitmproxy.tools.console.master.ConsoleMaster",
+ self,
+ master: "mitmproxy.tools.console.master.ConsoleMaster",
) -> None:
self.master = master
self.focus_changed()
@@ -49,45 +51,90 @@ class FlowDetails(tabs.Tabs):
self.show()
self.last_displayed_body = None
- def focus_changed(self):
- if self.master.view.focus.flow:
- self.tabs = [
- (self.tab_request, self.view_request),
- (self.tab_response, self.view_response),
- (self.tab_details, self.view_details),
- ]
- self.show()
- else:
- self.master.window.pop()
-
@property
def view(self):
return self.master.view
@property
- def flow(self):
+ def flow(self) -> mitmproxy.flow.Flow:
return self.master.view.focus.flow
- def tab_request(self):
- if self.flow.intercepted and not self.flow.response:
+ def focus_changed(self):
+ if self.flow:
+ if isinstance(self.flow, http.HTTPFlow):
+ self.tabs = [
+ (self.tab_http_request, self.view_request),
+ (self.tab_http_response, self.view_response),
+ (self.tab_details, self.view_details),
+ ]
+ elif isinstance(self.flow, tcp.TCPFlow):
+ self.tabs = [
+ (self.tab_tcp_stream, self.view_tcp_stream),
+ (self.tab_details, self.view_details),
+ ]
+ self.show()
+ else:
+ self.master.window.pop()
+
+ def tab_http_request(self):
+ flow = self.flow
+ assert isinstance(flow, http.HTTPFlow)
+ if self.flow.intercepted and not flow.response:
return "Request intercepted"
else:
return "Request"
- def tab_response(self):
- if self.flow.intercepted and self.flow.response:
+ def tab_http_response(self):
+ flow = self.flow
+ assert isinstance(flow, http.HTTPFlow)
+ if self.flow.intercepted and flow.response:
return "Response intercepted"
else:
return "Response"
+ def tab_tcp_stream(self):
+ return "TCP Stream"
+
def tab_details(self):
return "Detail"
def view_request(self):
- return self.conn_text(self.flow.request)
+ flow = self.flow
+ assert isinstance(flow, http.HTTPFlow)
+ return self.conn_text(flow.request)
def view_response(self):
- return self.conn_text(self.flow.response)
+ flow = self.flow
+ assert isinstance(flow, http.HTTPFlow)
+ return self.conn_text(flow.response)
+
+ def view_tcp_stream(self) -> urwid.Widget:
+ flow = self.flow
+ assert isinstance(flow, tcp.TCPFlow)
+
+ if not flow.messages:
+ return searchable.Searchable([urwid.Text(("highlight", "No messages."))])
+
+ from_client = None
+ messages = []
+ for message in flow.messages:
+ if message.from_client is not from_client:
+ messages.append(message.content)
+ from_client = message.from_client
+ else:
+ messages[-1] += message.content
+
+ from_client = flow.messages[0].from_client
+ parts = []
+ for message in messages:
+ parts.append(
+ (
+ "head" if from_client else "key",
+ message
+ )
+ )
+ from_client = not from_client
+ return searchable.Searchable([urwid.Text(parts)])
def view_details(self):
return flowdetailview.flowdetails(self.view, self.flow)
@@ -226,7 +273,7 @@ class FlowView(urwid.Frame, layoutwidget.LayoutWidget):
def __init__(self, master):
super().__init__(
FlowDetails(master),
- header = FlowViewHeader(master),
+ header=FlowViewHeader(master),
)
self.master = master