mirror of
https://github.com/Grasscutters/mitmproxy.git
synced 2024-11-26 18:18:25 +00:00
Merge pull request #1690 from cortesi/consoleview
console: Port from state to view
This commit is contained in:
commit
b229d470c4
@ -17,6 +17,7 @@ import sortedcontainers
|
|||||||
|
|
||||||
import mitmproxy.flow
|
import mitmproxy.flow
|
||||||
from mitmproxy import flowfilter
|
from mitmproxy import flowfilter
|
||||||
|
from mitmproxy import exceptions
|
||||||
|
|
||||||
|
|
||||||
def key_request_start(f: mitmproxy.flow.Flow) -> datetime.datetime:
|
def key_request_start(f: mitmproxy.flow.Flow) -> datetime.datetime:
|
||||||
@ -35,6 +36,8 @@ class View(collections.Sequence):
|
|||||||
super().__init__()
|
super().__init__()
|
||||||
self._store = {}
|
self._store = {}
|
||||||
self.filter = matchall
|
self.filter = matchall
|
||||||
|
# Should we show only marked flows?
|
||||||
|
self.show_marked = False
|
||||||
self.order_key = key_request_start
|
self.order_key = key_request_start
|
||||||
self.order_reversed = False
|
self.order_reversed = False
|
||||||
self._view = sortedcontainers.SortedListWithKey(key = self.order_key)
|
self._view = sortedcontainers.SortedListWithKey(key = self.order_key)
|
||||||
@ -51,6 +54,15 @@ class View(collections.Sequence):
|
|||||||
self.focus = Focus(self)
|
self.focus = Focus(self)
|
||||||
self.settings = Settings(self)
|
self.settings = Settings(self)
|
||||||
|
|
||||||
|
def store_count(self):
|
||||||
|
return len(self._store)
|
||||||
|
|
||||||
|
def inbounds(self, index: int) -> bool:
|
||||||
|
"""
|
||||||
|
Is this index >= 0 and < len(self)
|
||||||
|
"""
|
||||||
|
return index >= 0 and index < len(self)
|
||||||
|
|
||||||
def _rev(self, idx: int) -> int:
|
def _rev(self, idx: int) -> int:
|
||||||
"""
|
"""
|
||||||
Reverses an index, if needed
|
Reverses an index, if needed
|
||||||
@ -82,7 +94,19 @@ class View(collections.Sequence):
|
|||||||
def index(self, f: mitmproxy.flow.Flow) -> int:
|
def index(self, f: mitmproxy.flow.Flow) -> int:
|
||||||
return self._rev(self._view.index(f))
|
return self._rev(self._view.index(f))
|
||||||
|
|
||||||
|
def _refilter(self):
|
||||||
|
self._view.clear()
|
||||||
|
for i in self._store.values():
|
||||||
|
if self.show_marked and not i.marked:
|
||||||
|
continue
|
||||||
|
if self.filter(i):
|
||||||
|
self._view.add(i)
|
||||||
|
self.sig_refresh.send(self)
|
||||||
|
|
||||||
# API
|
# API
|
||||||
|
def toggle_marked(self):
|
||||||
|
self.show_marked = not self.show_marked
|
||||||
|
self._refilter()
|
||||||
|
|
||||||
def toggle_reversed(self):
|
def toggle_reversed(self):
|
||||||
self.order_reversed = not self.order_reversed
|
self.order_reversed = not self.order_reversed
|
||||||
@ -102,17 +126,13 @@ class View(collections.Sequence):
|
|||||||
Sets the current view filter.
|
Sets the current view filter.
|
||||||
"""
|
"""
|
||||||
self.filter = flt or matchall
|
self.filter = flt or matchall
|
||||||
self._view.clear()
|
self._refilter()
|
||||||
for i in self._store.values():
|
|
||||||
if self.filter(i):
|
|
||||||
self._view.add(i)
|
|
||||||
self.sig_refresh.send(self)
|
|
||||||
|
|
||||||
def clear(self):
|
def clear(self):
|
||||||
"""
|
"""
|
||||||
Clears both the state and view.
|
Clears both the state and view.
|
||||||
"""
|
"""
|
||||||
self._state.clear()
|
self._store.clear()
|
||||||
self._view.clear()
|
self._view.clear()
|
||||||
self.sig_refresh.send(self)
|
self.sig_refresh.send(self)
|
||||||
|
|
||||||
@ -157,6 +177,16 @@ class View(collections.Sequence):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
# Event handlers
|
# Event handlers
|
||||||
|
def configure(self, opts, updated):
|
||||||
|
filt = None
|
||||||
|
if "filter" in updated:
|
||||||
|
if opts.filter:
|
||||||
|
filt = flowfilter.parse(opts.filter)
|
||||||
|
if not filt:
|
||||||
|
raise exceptions.OptionsError(
|
||||||
|
"Invalid interception filter: %s" % opts.filter
|
||||||
|
)
|
||||||
|
self.set_filter(filt)
|
||||||
|
|
||||||
def request(self, f):
|
def request(self, f):
|
||||||
self.add(f)
|
self.add(f)
|
||||||
@ -202,21 +232,11 @@ class Focus:
|
|||||||
if self.flow:
|
if self.flow:
|
||||||
return self.view.index(self.flow)
|
return self.view.index(self.flow)
|
||||||
|
|
||||||
def next(self):
|
@index.setter
|
||||||
"""
|
def index(self, idx) -> typing.Optional[int]:
|
||||||
Sets the focus to the next flow.
|
if idx < 0 or idx > len(self.view) - 1:
|
||||||
"""
|
raise ValueError("Index out of view bounds")
|
||||||
if self.flow:
|
self.flow = self.view[idx]
|
||||||
idx = min(self.index + 1, len(self.view) - 1)
|
|
||||||
self.flow = self.view[idx]
|
|
||||||
|
|
||||||
def prev(self):
|
|
||||||
"""
|
|
||||||
Sets the focus to the previous flow.
|
|
||||||
"""
|
|
||||||
if self.flow:
|
|
||||||
idx = max(self.index - 1, 0)
|
|
||||||
self.flow = self.view[idx]
|
|
||||||
|
|
||||||
def _nearest(self, f, v):
|
def _nearest(self, f, v):
|
||||||
return min(v.bisect(f), len(v) - 1)
|
return min(v.bisect(f), len(v) - 1)
|
||||||
|
@ -109,8 +109,8 @@ class BodyPile(urwid.Pile):
|
|||||||
|
|
||||||
class ConnectionItem(urwid.WidgetWrap):
|
class ConnectionItem(urwid.WidgetWrap):
|
||||||
|
|
||||||
def __init__(self, master, state, flow, focus):
|
def __init__(self, master, view, flow, focus):
|
||||||
self.master, self.state, self.flow = master, state, flow
|
self.master, self.view, self.flow = master, view, flow
|
||||||
self.f = focus
|
self.f = focus
|
||||||
w = self.get_text()
|
w = self.get_text()
|
||||||
urwid.WidgetWrap.__init__(self, w)
|
urwid.WidgetWrap.__init__(self, w)
|
||||||
@ -143,7 +143,7 @@ class ConnectionItem(urwid.WidgetWrap):
|
|||||||
def server_replay_prompt(self, k):
|
def server_replay_prompt(self, k):
|
||||||
a = self.master.addons.get("serverplayback")
|
a = self.master.addons.get("serverplayback")
|
||||||
if k == "a":
|
if k == "a":
|
||||||
a.load([i.copy() for i in self.master.state.view])
|
a.load([i.copy() for i in self.master.view])
|
||||||
elif k == "t":
|
elif k == "t":
|
||||||
a.load([self.flow.copy()])
|
a.load([self.flow.copy()])
|
||||||
signals.update_settings.send(self)
|
signals.update_settings.send(self)
|
||||||
@ -163,21 +163,18 @@ class ConnectionItem(urwid.WidgetWrap):
|
|||||||
elif key == "d":
|
elif key == "d":
|
||||||
if self.flow.killable:
|
if self.flow.killable:
|
||||||
self.flow.kill(self.master)
|
self.flow.kill(self.master)
|
||||||
self.state.delete_flow(self.flow)
|
self.view.remove(self.view.focus.flow)
|
||||||
signals.flowlist_change.send(self)
|
signals.flowlist_change.send(self)
|
||||||
elif key == "D":
|
elif key == "D":
|
||||||
f = self.master.state.duplicate_flow(self.flow)
|
cp = self.flow.copy()
|
||||||
self.master.state.set_focus_flow(f)
|
self.master.view.add(cp)
|
||||||
|
self.master.view.focus.flow = cp
|
||||||
signals.flowlist_change.send(self)
|
signals.flowlist_change.send(self)
|
||||||
elif key == "m":
|
elif key == "m":
|
||||||
self.flow.marked = not self.flow.marked
|
self.flow.marked = not self.flow.marked
|
||||||
signals.flowlist_change.send(self)
|
signals.flowlist_change.send(self)
|
||||||
elif key == "M":
|
elif key == "M":
|
||||||
if self.state.mark_filter:
|
self.master.view.toggle_marked()
|
||||||
self.state.disable_marked_filter()
|
|
||||||
else:
|
|
||||||
self.state.enable_marked_filter()
|
|
||||||
signals.flowlist_change.send(self)
|
|
||||||
elif key == "r":
|
elif key == "r":
|
||||||
try:
|
try:
|
||||||
self.master.replay_request(self.flow)
|
self.master.replay_request(self.flow)
|
||||||
@ -208,14 +205,14 @@ class ConnectionItem(urwid.WidgetWrap):
|
|||||||
callback = self.server_replay_prompt,
|
callback = self.server_replay_prompt,
|
||||||
)
|
)
|
||||||
elif key == "U":
|
elif key == "U":
|
||||||
for f in self.state.flows:
|
for f in self.view:
|
||||||
f.marked = False
|
f.marked = False
|
||||||
signals.flowlist_change.send(self)
|
signals.flowlist_change.send(self)
|
||||||
elif key == "V":
|
elif key == "V":
|
||||||
if not self.flow.modified():
|
if not self.flow.modified():
|
||||||
signals.status_message.send(message="Flow not modified.")
|
signals.status_message.send(message="Flow not modified.")
|
||||||
return
|
return
|
||||||
self.state.revert(self.flow)
|
self.flow.revert()
|
||||||
signals.flowlist_change.send(self)
|
signals.flowlist_change.send(self)
|
||||||
signals.status_message.send(message="Reverted.")
|
signals.status_message.send(message="Reverted.")
|
||||||
elif key == "w":
|
elif key == "w":
|
||||||
@ -264,38 +261,49 @@ class ConnectionItem(urwid.WidgetWrap):
|
|||||||
|
|
||||||
class FlowListWalker(urwid.ListWalker):
|
class FlowListWalker(urwid.ListWalker):
|
||||||
|
|
||||||
def __init__(self, master, state):
|
def __init__(self, master, view):
|
||||||
self.master, self.state = master, state
|
self.master, self.view = master, view
|
||||||
signals.flowlist_change.connect(self.sig_flowlist_change)
|
self.view.sig_refresh.connect(self.sig_mod)
|
||||||
|
self.view.sig_add.connect(self.sig_mod)
|
||||||
|
self.view.sig_remove.connect(self.sig_mod)
|
||||||
|
self.view.sig_update.connect(self.sig_mod)
|
||||||
|
signals.flowlist_change.connect(self.sig_mod)
|
||||||
|
|
||||||
def sig_flowlist_change(self, sender):
|
def sig_mod(self, *args, **kwargs):
|
||||||
self._modified()
|
self._modified()
|
||||||
|
|
||||||
def get_focus(self):
|
def get_focus(self):
|
||||||
f, i = self.state.get_focus()
|
if not self.view.focus.flow:
|
||||||
f = ConnectionItem(self.master, self.state, f, True) if f else None
|
return None, 0
|
||||||
return f, i
|
return ConnectionItem(
|
||||||
|
self.master, self.view, self.view.focus.flow, True
|
||||||
|
), self.view.focus.index
|
||||||
|
|
||||||
def set_focus(self, focus):
|
def set_focus(self, index):
|
||||||
ret = self.state.set_focus(focus)
|
if self.view.inbounds(index):
|
||||||
return ret
|
self.view.focus.index = index
|
||||||
|
signals.flowlist_change.send(self)
|
||||||
|
|
||||||
def get_next(self, pos):
|
def get_next(self, pos):
|
||||||
f, i = self.state.get_next(pos)
|
pos = pos + 1
|
||||||
f = ConnectionItem(self.master, self.state, f, False) if f else None
|
if not self.view.inbounds(pos):
|
||||||
return f, i
|
return None, None
|
||||||
|
f = ConnectionItem(self.master, self.view, self.view[pos], False)
|
||||||
|
return f, pos
|
||||||
|
|
||||||
def get_prev(self, pos):
|
def get_prev(self, pos):
|
||||||
f, i = self.state.get_prev(pos)
|
pos = pos - 1
|
||||||
f = ConnectionItem(self.master, self.state, f, False) if f else None
|
if not self.view.inbounds(pos):
|
||||||
return f, i
|
return None, None
|
||||||
|
f = ConnectionItem(self.master, self.view, self.view[pos], False)
|
||||||
|
return f, pos
|
||||||
|
|
||||||
|
|
||||||
class FlowListBox(urwid.ListBox):
|
class FlowListBox(urwid.ListBox):
|
||||||
|
|
||||||
def __init__(self, master: "mitmproxy.console.master.ConsoleMaster"):
|
def __init__(self, master: "mitmproxy.console.master.ConsoleMaster"):
|
||||||
self.master = master
|
self.master = master
|
||||||
super().__init__(FlowListWalker(master, master.state))
|
super().__init__(FlowListWalker(master, master.view))
|
||||||
|
|
||||||
def get_method_raw(self, k):
|
def get_method_raw(self, k):
|
||||||
if k:
|
if k:
|
||||||
@ -331,29 +339,32 @@ class FlowListBox(urwid.ListBox):
|
|||||||
return
|
return
|
||||||
scheme, host, port, path = parts
|
scheme, host, port, path = parts
|
||||||
f = self.master.create_request(method, scheme, host, port, path)
|
f = self.master.create_request(method, scheme, host, port, path)
|
||||||
self.master.state.set_focus_flow(f)
|
self.master.view.focus.flow = f
|
||||||
signals.flowlist_change.send(self)
|
signals.flowlist_change.send(self)
|
||||||
|
|
||||||
def keypress(self, size, key):
|
def keypress(self, size, key):
|
||||||
key = common.shortcuts(key)
|
key = common.shortcuts(key)
|
||||||
if key == "A":
|
if key == "A":
|
||||||
self.master.accept_all()
|
for f in self.master.view:
|
||||||
|
if f.intercepted:
|
||||||
|
f.resume()
|
||||||
signals.flowlist_change.send(self)
|
signals.flowlist_change.send(self)
|
||||||
elif key == "z":
|
elif key == "z":
|
||||||
self.master.clear_flows()
|
self.master.view.clear()
|
||||||
|
signals.flowlist_change.send(self)
|
||||||
elif key == "e":
|
elif key == "e":
|
||||||
self.master.toggle_eventlog()
|
self.master.toggle_eventlog()
|
||||||
elif key == "g":
|
elif key == "g":
|
||||||
self.master.state.set_focus(0)
|
self.master.view.focus.index = 0
|
||||||
signals.flowlist_change.send(self)
|
signals.flowlist_change.send(self)
|
||||||
elif key == "G":
|
elif key == "G":
|
||||||
self.master.state.set_focus(self.master.state.flow_count())
|
self.master.view.focus.index = len(self.master.view) - 1
|
||||||
signals.flowlist_change.send(self)
|
signals.flowlist_change.send(self)
|
||||||
elif key == "f":
|
elif key == "f":
|
||||||
signals.status_prompt.send(
|
signals.status_prompt.send(
|
||||||
prompt = "Filter View",
|
prompt = "Filter View",
|
||||||
text = self.master.state.filter_txt,
|
text = self.master.options.filter,
|
||||||
callback = self.master.set_view_filter
|
callback = self.master.options.setter("filter")
|
||||||
)
|
)
|
||||||
elif key == "L":
|
elif key == "L":
|
||||||
signals.status_prompt_path.send(
|
signals.status_prompt_path.send(
|
||||||
|
@ -127,8 +127,8 @@ TAB_RESP = 1
|
|||||||
class FlowView(tabs.Tabs):
|
class FlowView(tabs.Tabs):
|
||||||
highlight_color = "focusfield"
|
highlight_color = "focusfield"
|
||||||
|
|
||||||
def __init__(self, master, state, flow, tab_offset):
|
def __init__(self, master, view, flow, tab_offset):
|
||||||
self.master, self.state, self.flow = master, state, flow
|
self.master, self.view, self.flow = master, view, flow
|
||||||
super().__init__(
|
super().__init__(
|
||||||
[
|
[
|
||||||
(self.tab_request, self.view_request),
|
(self.tab_request, self.view_request),
|
||||||
@ -164,7 +164,7 @@ class FlowView(tabs.Tabs):
|
|||||||
return self.conn_text(self.flow.response)
|
return self.conn_text(self.flow.response)
|
||||||
|
|
||||||
def view_details(self):
|
def view_details(self):
|
||||||
return flowdetailview.flowdetails(self.state, self.flow)
|
return flowdetailview.flowdetails(self.view, self.flow)
|
||||||
|
|
||||||
def sig_flow_change(self, sender, flow):
|
def sig_flow_change(self, sender, flow):
|
||||||
if flow == self.flow:
|
if flow == self.flow:
|
||||||
@ -175,11 +175,8 @@ class FlowView(tabs.Tabs):
|
|||||||
msg, body = "", [urwid.Text([("error", "[content missing]")])]
|
msg, body = "", [urwid.Text([("error", "[content missing]")])]
|
||||||
return msg, body
|
return msg, body
|
||||||
else:
|
else:
|
||||||
full = self.state.get_flow_setting(
|
s = self.view.settings[self.flow]
|
||||||
self.flow,
|
full = s.get((self.tab_offset, "fullcontents"), False)
|
||||||
(self.tab_offset, "fullcontents"),
|
|
||||||
False
|
|
||||||
)
|
|
||||||
if full:
|
if full:
|
||||||
limit = sys.maxsize
|
limit = sys.maxsize
|
||||||
else:
|
else:
|
||||||
@ -237,9 +234,9 @@ class FlowView(tabs.Tabs):
|
|||||||
return description, text_objects
|
return description, text_objects
|
||||||
|
|
||||||
def viewmode_get(self):
|
def viewmode_get(self):
|
||||||
override = self.state.get_flow_setting(
|
override = self.view.settings[self.flow].get(
|
||||||
self.flow,
|
(self.tab_offset, "prettyview"),
|
||||||
(self.tab_offset, "prettyview")
|
None
|
||||||
)
|
)
|
||||||
return self.master.options.default_contentview if override is None else override
|
return self.master.options.default_contentview if override is None else override
|
||||||
|
|
||||||
@ -284,7 +281,7 @@ class FlowView(tabs.Tabs):
|
|||||||
]
|
]
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
return searchable.Searchable(self.state, txt)
|
return searchable.Searchable(self.view, txt)
|
||||||
|
|
||||||
def set_method_raw(self, m):
|
def set_method_raw(self, m):
|
||||||
if m:
|
if m:
|
||||||
@ -466,33 +463,25 @@ class FlowView(tabs.Tabs):
|
|||||||
)
|
)
|
||||||
signals.flow_change.send(self, flow = self.flow)
|
signals.flow_change.send(self, flow = self.flow)
|
||||||
|
|
||||||
def _view_nextprev_flow(self, np, flow):
|
def view_flow(self, flow):
|
||||||
try:
|
signals.pop_view_state.send(self)
|
||||||
idx = self.state.view.index(flow)
|
self.master.view_flow(flow, self.tab_offset)
|
||||||
except IndexError:
|
|
||||||
return
|
def _view_nextprev_flow(self, idx, flow):
|
||||||
if np == "next":
|
if not self.view.inbounds(idx):
|
||||||
new_flow, new_idx = self.state.get_next(idx)
|
|
||||||
else:
|
|
||||||
new_flow, new_idx = self.state.get_prev(idx)
|
|
||||||
if new_flow is None:
|
|
||||||
signals.status_message.send(message="No more flows")
|
signals.status_message.send(message="No more flows")
|
||||||
else:
|
return
|
||||||
signals.pop_view_state.send(self)
|
self.view_flow(self.view[idx])
|
||||||
self.master.view_flow(new_flow, self.tab_offset)
|
|
||||||
|
|
||||||
def view_next_flow(self, flow):
|
def view_next_flow(self, flow):
|
||||||
return self._view_nextprev_flow("next", flow)
|
return self._view_nextprev_flow(self.view.index(flow) + 1, flow)
|
||||||
|
|
||||||
def view_prev_flow(self, flow):
|
def view_prev_flow(self, flow):
|
||||||
return self._view_nextprev_flow("prev", flow)
|
return self._view_nextprev_flow(self.view.index(flow) - 1, flow)
|
||||||
|
|
||||||
def change_this_display_mode(self, t):
|
def change_this_display_mode(self, t):
|
||||||
self.state.add_flow_setting(
|
name = contentviews.get_by_shortcut(t).name
|
||||||
self.flow,
|
self.view.settings[self.flow][(self.tab_offset, "prettyview")] = name
|
||||||
(self.tab_offset, "prettyview"),
|
|
||||||
contentviews.get_by_shortcut(t).name
|
|
||||||
)
|
|
||||||
signals.flow_change.send(self, flow = self.flow)
|
signals.flow_change.send(self, flow = self.flow)
|
||||||
|
|
||||||
def keypress(self, size, key):
|
def keypress(self, size, key):
|
||||||
@ -521,20 +510,18 @@ class FlowView(tabs.Tabs):
|
|||||||
self.master.accept_all()
|
self.master.accept_all()
|
||||||
signals.flow_change.send(self, flow = self.flow)
|
signals.flow_change.send(self, flow = self.flow)
|
||||||
elif key == "d":
|
elif key == "d":
|
||||||
if self.state.flow_count() == 1:
|
if self.flow.killable:
|
||||||
|
self.flow.kill(self.master)
|
||||||
|
self.view.remove(self.flow)
|
||||||
|
if not self.view.focus.flow:
|
||||||
self.master.view_flowlist()
|
self.master.view_flowlist()
|
||||||
elif self.state.view.index(self.flow) == len(self.state.view) - 1:
|
|
||||||
self.view_prev_flow(self.flow)
|
|
||||||
else:
|
else:
|
||||||
self.view_next_flow(self.flow)
|
self.view_flow(self.view.focus.flow)
|
||||||
f = self.flow
|
|
||||||
if f.killable:
|
|
||||||
f.kill(self.master)
|
|
||||||
self.state.delete_flow(f)
|
|
||||||
elif key == "D":
|
elif key == "D":
|
||||||
f = self.master.state.duplicate_flow(self.flow)
|
cp = self.flow.copy()
|
||||||
signals.pop_view_state.send(self)
|
self.master.view.add(cp)
|
||||||
self.master.view_flow(f)
|
self.master.view.focus.flow = cp
|
||||||
|
self.view_flow(cp)
|
||||||
signals.status_message.send(message="Duplicated.")
|
signals.status_message.send(message="Duplicated.")
|
||||||
elif key == "p":
|
elif key == "p":
|
||||||
self.view_prev_flow(self.flow)
|
self.view_prev_flow(self.flow)
|
||||||
@ -546,7 +533,7 @@ class FlowView(tabs.Tabs):
|
|||||||
signals.flow_change.send(self, flow = self.flow)
|
signals.flow_change.send(self, flow = self.flow)
|
||||||
elif key == "V":
|
elif key == "V":
|
||||||
if self.flow.modified():
|
if self.flow.modified():
|
||||||
self.state.revert(self.flow)
|
self.flow.revert()
|
||||||
signals.flow_change.send(self, flow = self.flow)
|
signals.flow_change.send(self, flow = self.flow)
|
||||||
signals.status_message.send(message="Reverted.")
|
signals.status_message.send(message="Reverted.")
|
||||||
else:
|
else:
|
||||||
@ -608,14 +595,9 @@ class FlowView(tabs.Tabs):
|
|||||||
else:
|
else:
|
||||||
common.ask_save_body("s", self.flow)
|
common.ask_save_body("s", self.flow)
|
||||||
elif key == "f":
|
elif key == "f":
|
||||||
signals.status_message.send(message="Loading all body data...")
|
self.view.settings[self.flow][(self.tab_offset, "fullcontents")] = True
|
||||||
self.state.add_flow_setting(
|
|
||||||
self.flow,
|
|
||||||
(self.tab_offset, "fullcontents"),
|
|
||||||
True
|
|
||||||
)
|
|
||||||
signals.flow_change.send(self, flow = self.flow)
|
signals.flow_change.send(self, flow = self.flow)
|
||||||
signals.status_message.send(message="")
|
signals.status_message.send(message="Loading all body data...")
|
||||||
elif key == "m":
|
elif key == "m":
|
||||||
p = list(contentviews.view_prompts)
|
p = list(contentviews.view_prompts)
|
||||||
p.insert(0, ("Clear", "C"))
|
p.insert(0, ("Clear", "C"))
|
||||||
|
@ -9,7 +9,6 @@ import subprocess
|
|||||||
import sys
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
import traceback
|
import traceback
|
||||||
import weakref
|
|
||||||
|
|
||||||
import urwid
|
import urwid
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
@ -19,9 +18,8 @@ from mitmproxy import controller
|
|||||||
from mitmproxy import exceptions
|
from mitmproxy import exceptions
|
||||||
from mitmproxy import master
|
from mitmproxy import master
|
||||||
from mitmproxy import io
|
from mitmproxy import io
|
||||||
from mitmproxy import flowfilter
|
|
||||||
from mitmproxy import log
|
from mitmproxy import log
|
||||||
from mitmproxy.addons import state
|
from mitmproxy.addons import view
|
||||||
from mitmproxy.addons import intercept
|
from mitmproxy.addons import intercept
|
||||||
import mitmproxy.options
|
import mitmproxy.options
|
||||||
from mitmproxy.tools.console import flowlist
|
from mitmproxy.tools.console import flowlist
|
||||||
@ -34,7 +32,6 @@ from mitmproxy.tools.console import palettes
|
|||||||
from mitmproxy.tools.console import signals
|
from mitmproxy.tools.console import signals
|
||||||
from mitmproxy.tools.console import statusbar
|
from mitmproxy.tools.console import statusbar
|
||||||
from mitmproxy.tools.console import window
|
from mitmproxy.tools.console import window
|
||||||
from mitmproxy.flowfilter import FMarked
|
|
||||||
from mitmproxy.utils import strutils
|
from mitmproxy.utils import strutils
|
||||||
|
|
||||||
from mitmproxy.net import tcp
|
from mitmproxy.net import tcp
|
||||||
@ -42,163 +39,6 @@ from mitmproxy.net import tcp
|
|||||||
EVENTLOG_SIZE = 500
|
EVENTLOG_SIZE = 500
|
||||||
|
|
||||||
|
|
||||||
class ConsoleState(state.State):
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
state.State.__init__(self)
|
|
||||||
self.focus = None
|
|
||||||
self.follow_focus = None
|
|
||||||
self.flowsettings = weakref.WeakKeyDictionary()
|
|
||||||
self.last_search = None
|
|
||||||
self.last_filter = ""
|
|
||||||
self.mark_filter = False
|
|
||||||
|
|
||||||
def __setattr__(self, name, value):
|
|
||||||
self.__dict__[name] = value
|
|
||||||
signals.update_settings.send(self)
|
|
||||||
|
|
||||||
def add_flow_setting(self, flow, key, value):
|
|
||||||
d = self.flowsettings.setdefault(flow, {})
|
|
||||||
d[key] = value
|
|
||||||
|
|
||||||
def get_flow_setting(self, flow, key, default=None):
|
|
||||||
d = self.flowsettings.get(flow, {})
|
|
||||||
return d.get(key, default)
|
|
||||||
|
|
||||||
def add_flow(self, f):
|
|
||||||
super().add_flow(f)
|
|
||||||
signals.flowlist_change.send(self)
|
|
||||||
self.update_focus()
|
|
||||||
return f
|
|
||||||
|
|
||||||
def update_flow(self, f):
|
|
||||||
super().update_flow(f)
|
|
||||||
signals.flowlist_change.send(self)
|
|
||||||
self.update_focus()
|
|
||||||
return f
|
|
||||||
|
|
||||||
def set_view_filter(self, txt):
|
|
||||||
ret = super().set_view_filter(txt)
|
|
||||||
self.set_focus(self.focus)
|
|
||||||
return ret
|
|
||||||
|
|
||||||
def get_focus(self):
|
|
||||||
if not self.view or self.focus is None:
|
|
||||||
return None, None
|
|
||||||
return self.view[self.focus], self.focus
|
|
||||||
|
|
||||||
def set_focus(self, idx):
|
|
||||||
if self.view:
|
|
||||||
if idx is None or idx < 0:
|
|
||||||
idx = 0
|
|
||||||
elif idx >= len(self.view):
|
|
||||||
idx = len(self.view) - 1
|
|
||||||
self.focus = idx
|
|
||||||
else:
|
|
||||||
self.focus = None
|
|
||||||
|
|
||||||
def update_focus(self):
|
|
||||||
if self.focus is None:
|
|
||||||
self.set_focus(0)
|
|
||||||
elif self.follow_focus:
|
|
||||||
self.set_focus(len(self.view) - 1)
|
|
||||||
|
|
||||||
def set_focus_flow(self, f):
|
|
||||||
self.set_focus(self.view.index(f))
|
|
||||||
|
|
||||||
def get_from_pos(self, pos):
|
|
||||||
if len(self.view) <= pos or pos < 0:
|
|
||||||
return None, None
|
|
||||||
return self.view[pos], pos
|
|
||||||
|
|
||||||
def get_next(self, pos):
|
|
||||||
return self.get_from_pos(pos + 1)
|
|
||||||
|
|
||||||
def get_prev(self, pos):
|
|
||||||
return self.get_from_pos(pos - 1)
|
|
||||||
|
|
||||||
def delete_flow(self, f):
|
|
||||||
if f in self.view and self.view.index(f) <= self.focus:
|
|
||||||
self.focus -= 1
|
|
||||||
if self.focus < 0:
|
|
||||||
self.focus = None
|
|
||||||
ret = super().delete_flow(f)
|
|
||||||
self.set_focus(self.focus)
|
|
||||||
return ret
|
|
||||||
|
|
||||||
def get_nearest_matching_flow(self, flow, flt):
|
|
||||||
fidx = self.view.index(flow)
|
|
||||||
dist = 1
|
|
||||||
|
|
||||||
fprev = fnext = True
|
|
||||||
while fprev or fnext:
|
|
||||||
fprev, _ = self.get_from_pos(fidx - dist)
|
|
||||||
fnext, _ = self.get_from_pos(fidx + dist)
|
|
||||||
|
|
||||||
if fprev and flowfilter.match(flt, fprev):
|
|
||||||
return fprev
|
|
||||||
elif fnext and flowfilter.match(flt, fnext):
|
|
||||||
return fnext
|
|
||||||
|
|
||||||
dist += 1
|
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
def enable_marked_filter(self):
|
|
||||||
marked_flows = [f for f in self.flows if f.marked]
|
|
||||||
if not marked_flows:
|
|
||||||
return
|
|
||||||
|
|
||||||
marked_filter = "~%s" % FMarked.code
|
|
||||||
|
|
||||||
# Save Focus
|
|
||||||
last_focus, _ = self.get_focus()
|
|
||||||
nearest_marked = self.get_nearest_matching_flow(last_focus, marked_filter)
|
|
||||||
|
|
||||||
self.last_filter = self.filter_txt
|
|
||||||
self.set_view_filter(marked_filter)
|
|
||||||
|
|
||||||
# Restore Focus
|
|
||||||
if last_focus.marked:
|
|
||||||
self.set_focus_flow(last_focus)
|
|
||||||
else:
|
|
||||||
self.set_focus_flow(nearest_marked)
|
|
||||||
|
|
||||||
self.mark_filter = True
|
|
||||||
|
|
||||||
def disable_marked_filter(self):
|
|
||||||
marked_filter = "~%s" % FMarked.code
|
|
||||||
|
|
||||||
# Save Focus
|
|
||||||
last_focus, _ = self.get_focus()
|
|
||||||
nearest_marked = self.get_nearest_matching_flow(last_focus, marked_filter)
|
|
||||||
|
|
||||||
self.set_view_filter(self.last_filter)
|
|
||||||
self.last_filter = ""
|
|
||||||
|
|
||||||
# Restore Focus
|
|
||||||
if last_focus.marked:
|
|
||||||
self.set_focus_flow(last_focus)
|
|
||||||
else:
|
|
||||||
self.set_focus_flow(nearest_marked)
|
|
||||||
|
|
||||||
self.mark_filter = False
|
|
||||||
|
|
||||||
def clear(self):
|
|
||||||
marked_flows = [f for f in self.view if f.marked]
|
|
||||||
super().clear()
|
|
||||||
|
|
||||||
for f in marked_flows:
|
|
||||||
self.add_flow(f)
|
|
||||||
f.marked = True
|
|
||||||
|
|
||||||
if len(self.flows.views) == 0:
|
|
||||||
self.focus = None
|
|
||||||
else:
|
|
||||||
self.focus = 0
|
|
||||||
self.set_focus(self.focus)
|
|
||||||
|
|
||||||
|
|
||||||
class Options(mitmproxy.options.Options):
|
class Options(mitmproxy.options.Options):
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
@ -210,6 +50,7 @@ class Options(mitmproxy.options.Options):
|
|||||||
palette: Optional[str] = None,
|
palette: Optional[str] = None,
|
||||||
palette_transparent: bool = False,
|
palette_transparent: bool = False,
|
||||||
no_mouse: bool = False,
|
no_mouse: bool = False,
|
||||||
|
follow_focus: bool = False,
|
||||||
**kwargs
|
**kwargs
|
||||||
):
|
):
|
||||||
self.eventlog = eventlog
|
self.eventlog = eventlog
|
||||||
@ -219,6 +60,7 @@ class Options(mitmproxy.options.Options):
|
|||||||
self.palette = palette
|
self.palette = palette
|
||||||
self.palette_transparent = palette_transparent
|
self.palette_transparent = palette_transparent
|
||||||
self.no_mouse = no_mouse
|
self.no_mouse = no_mouse
|
||||||
|
self.follow_focus = follow_focus
|
||||||
super().__init__(**kwargs)
|
super().__init__(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
@ -227,15 +69,12 @@ class ConsoleMaster(master.Master):
|
|||||||
|
|
||||||
def __init__(self, options, server):
|
def __init__(self, options, server):
|
||||||
super().__init__(options, server)
|
super().__init__(options, server)
|
||||||
self.state = ConsoleState()
|
self.view = view.View()
|
||||||
self.stream_path = None
|
self.stream_path = None
|
||||||
# This line is just for type hinting
|
# This line is just for type hinting
|
||||||
self.options = self.options # type: Options
|
self.options = self.options # type: Options
|
||||||
self.options.errored.connect(self.options_error)
|
self.options.errored.connect(self.options_error)
|
||||||
|
|
||||||
if options.filter:
|
|
||||||
self.set_view_filter(options.filter)
|
|
||||||
|
|
||||||
self.palette = options.palette
|
self.palette = options.palette
|
||||||
self.palette_transparent = options.palette_transparent
|
self.palette_transparent = options.palette_transparent
|
||||||
|
|
||||||
@ -250,7 +89,7 @@ class ConsoleMaster(master.Master):
|
|||||||
signals.push_view_state.connect(self.sig_push_view_state)
|
signals.push_view_state.connect(self.sig_push_view_state)
|
||||||
signals.sig_add_log.connect(self.sig_add_log)
|
signals.sig_add_log.connect(self.sig_add_log)
|
||||||
self.addons.add(*addons.default_addons())
|
self.addons.add(*addons.default_addons())
|
||||||
self.addons.add(self.state, intercept.Intercept())
|
self.addons.add(intercept.Intercept(), self.view)
|
||||||
|
|
||||||
def __setattr__(self, name, value):
|
def __setattr__(self, name, value):
|
||||||
self.__dict__[name] = value
|
self.__dict__[name] = value
|
||||||
@ -432,13 +271,13 @@ class ConsoleMaster(master.Master):
|
|||||||
|
|
||||||
if self.options.rfile:
|
if self.options.rfile:
|
||||||
ret = self.load_flows_path(self.options.rfile)
|
ret = self.load_flows_path(self.options.rfile)
|
||||||
if ret and self.state.flow_count():
|
if ret and self.view.store_count():
|
||||||
signals.add_log(
|
signals.add_log(
|
||||||
"File truncated or corrupted. "
|
"File truncated or corrupted. "
|
||||||
"Loaded as many flows as possible.",
|
"Loaded as many flows as possible.",
|
||||||
"error"
|
"error"
|
||||||
)
|
)
|
||||||
elif ret and not self.state.flow_count():
|
elif ret and not self.view.store_count():
|
||||||
self.shutdown()
|
self.shutdown()
|
||||||
print("Could not load file: {}".format(ret), file=sys.stderr)
|
print("Could not load file: {}".format(ret), file=sys.stderr)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
@ -533,17 +372,12 @@ class ConsoleMaster(master.Master):
|
|||||||
def view_flowlist(self):
|
def view_flowlist(self):
|
||||||
if self.ui.started:
|
if self.ui.started:
|
||||||
self.ui.clear()
|
self.ui.clear()
|
||||||
if self.state.follow_focus:
|
|
||||||
self.state.set_focus(self.state.flow_count())
|
|
||||||
|
|
||||||
if self.options.eventlog:
|
if self.options.eventlog:
|
||||||
body = flowlist.BodyPile(self)
|
body = flowlist.BodyPile(self)
|
||||||
else:
|
else:
|
||||||
body = flowlist.FlowListBox(self)
|
body = flowlist.FlowListBox(self)
|
||||||
|
|
||||||
if self.follow:
|
|
||||||
self.toggle_follow_flows()
|
|
||||||
|
|
||||||
signals.push_view_state.send(
|
signals.push_view_state.send(
|
||||||
self,
|
self,
|
||||||
window = window.Window(
|
window = window.Window(
|
||||||
@ -556,12 +390,12 @@ class ConsoleMaster(master.Master):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def view_flow(self, flow, tab_offset=0):
|
def view_flow(self, flow, tab_offset=0):
|
||||||
self.state.set_focus_flow(flow)
|
self.view.focus.flow = flow
|
||||||
signals.push_view_state.send(
|
signals.push_view_state.send(
|
||||||
self,
|
self,
|
||||||
window = window.Window(
|
window = window.Window(
|
||||||
self,
|
self,
|
||||||
flowview.FlowView(self, self.state, flow, tab_offset),
|
flowview.FlowView(self, self.view, flow, tab_offset),
|
||||||
flowview.FlowViewHeader(self, flow),
|
flowview.FlowViewHeader(self, flow),
|
||||||
statusbar.StatusBar(self, flowview.footer),
|
statusbar.StatusBar(self, flowview.footer),
|
||||||
flowview.help_context
|
flowview.help_context
|
||||||
@ -585,7 +419,7 @@ class ConsoleMaster(master.Master):
|
|||||||
return self._write_flows(path, [flow])
|
return self._write_flows(path, [flow])
|
||||||
|
|
||||||
def save_flows(self, path):
|
def save_flows(self, path):
|
||||||
return self._write_flows(path, self.state.view)
|
return self._write_flows(path, self.view)
|
||||||
|
|
||||||
def load_flows_callback(self, path):
|
def load_flows_callback(self, path):
|
||||||
if not path:
|
if not path:
|
||||||
@ -602,14 +436,6 @@ class ConsoleMaster(master.Master):
|
|||||||
signals.flowlist_change.send(self)
|
signals.flowlist_change.send(self)
|
||||||
return reterr
|
return reterr
|
||||||
|
|
||||||
def accept_all(self):
|
|
||||||
self.state.accept_all(self)
|
|
||||||
|
|
||||||
def set_view_filter(self, txt):
|
|
||||||
v = self.state.set_view_filter(txt)
|
|
||||||
signals.flowlist_change.send(self)
|
|
||||||
return v
|
|
||||||
|
|
||||||
def edit_scripts(self, scripts):
|
def edit_scripts(self, scripts):
|
||||||
self.options.scripts = [x[0] for x in scripts]
|
self.options.scripts = [x[0] for x in scripts]
|
||||||
|
|
||||||
@ -617,56 +443,14 @@ class ConsoleMaster(master.Master):
|
|||||||
if a != "n":
|
if a != "n":
|
||||||
raise urwid.ExitMainLoop
|
raise urwid.ExitMainLoop
|
||||||
|
|
||||||
def shutdown(self):
|
|
||||||
self.state.killall(self)
|
|
||||||
master.Master.shutdown(self)
|
|
||||||
|
|
||||||
def clear_flows(self):
|
|
||||||
self.state.clear()
|
|
||||||
signals.flowlist_change.send(self)
|
|
||||||
|
|
||||||
def toggle_follow_flows(self):
|
|
||||||
# toggle flow follow
|
|
||||||
self.state.follow_focus = not self.state.follow_focus
|
|
||||||
# jump to most recent flow if follow is now on
|
|
||||||
if self.state.follow_focus:
|
|
||||||
self.state.set_focus(self.state.flow_count())
|
|
||||||
signals.flowlist_change.send(self)
|
|
||||||
|
|
||||||
def delete_flow(self, f):
|
|
||||||
self.state.delete_flow(f)
|
|
||||||
signals.flowlist_change.send(self)
|
|
||||||
|
|
||||||
def refresh_focus(self):
|
def refresh_focus(self):
|
||||||
if self.state.view:
|
if self.view.focus.flow:
|
||||||
signals.flow_change.send(
|
signals.flow_change.send(self, flow = self.view.focus.flow)
|
||||||
self,
|
|
||||||
flow = self.state.view[self.state.focus]
|
|
||||||
)
|
|
||||||
|
|
||||||
def process_flow(self, f):
|
|
||||||
signals.flowlist_change.send(self)
|
|
||||||
signals.flow_change.send(self, flow=f)
|
|
||||||
|
|
||||||
def clear_events(self):
|
def clear_events(self):
|
||||||
self.logbuffer[:] = []
|
self.logbuffer[:] = []
|
||||||
|
|
||||||
# Handlers
|
# Handlers
|
||||||
@controller.handler
|
|
||||||
def error(self, f):
|
|
||||||
super().error(f)
|
|
||||||
self.process_flow(f)
|
|
||||||
|
|
||||||
@controller.handler
|
|
||||||
def request(self, f):
|
|
||||||
super().request(f)
|
|
||||||
self.process_flow(f)
|
|
||||||
|
|
||||||
@controller.handler
|
|
||||||
def response(self, f):
|
|
||||||
super().response(f)
|
|
||||||
self.process_flow(f)
|
|
||||||
|
|
||||||
@controller.handler
|
@controller.handler
|
||||||
def tcp_message(self, f):
|
def tcp_message(self, f):
|
||||||
super().tcp_message(f)
|
super().tcp_message(f)
|
||||||
|
@ -172,10 +172,8 @@ class Options(urwid.WidgetWrap):
|
|||||||
showhost = False,
|
showhost = False,
|
||||||
stickyauth = None,
|
stickyauth = None,
|
||||||
stickycookie = None,
|
stickycookie = None,
|
||||||
|
default_contentview = "auto",
|
||||||
)
|
)
|
||||||
|
|
||||||
self.master.state.default_body_view = contentviews.get("Auto")
|
|
||||||
|
|
||||||
signals.update_settings.send(self)
|
signals.update_settings.send(self)
|
||||||
signals.status_message.send(
|
signals.status_message.send(
|
||||||
message = "All select.Options cleared",
|
message = "All select.Options cleared",
|
||||||
|
@ -16,13 +16,14 @@ class Highlight(urwid.AttrMap):
|
|||||||
|
|
||||||
class Searchable(urwid.ListBox):
|
class Searchable(urwid.ListBox):
|
||||||
|
|
||||||
def __init__(self, state, contents):
|
def __init__(self, view, contents):
|
||||||
self.walker = urwid.SimpleFocusListWalker(contents)
|
self.walker = urwid.SimpleFocusListWalker(contents)
|
||||||
urwid.ListBox.__init__(self, self.walker)
|
urwid.ListBox.__init__(self, self.walker)
|
||||||
self.state = state
|
self.view = view
|
||||||
self.search_offset = 0
|
self.search_offset = 0
|
||||||
self.current_highlight = None
|
self.current_highlight = None
|
||||||
self.search_term = None
|
self.search_term = None
|
||||||
|
self.last_search = None
|
||||||
|
|
||||||
def keypress(self, size, key):
|
def keypress(self, size, key):
|
||||||
if key == "/":
|
if key == "/":
|
||||||
@ -45,7 +46,7 @@ class Searchable(urwid.ListBox):
|
|||||||
return super().keypress(size, key)
|
return super().keypress(size, key)
|
||||||
|
|
||||||
def set_search(self, text):
|
def set_search(self, text):
|
||||||
self.state.last_search = text
|
self.last_search = text
|
||||||
self.search_term = text or None
|
self.search_term = text or None
|
||||||
self.find_next(False)
|
self.find_next(False)
|
||||||
|
|
||||||
@ -69,8 +70,8 @@ class Searchable(urwid.ListBox):
|
|||||||
|
|
||||||
def find_next(self, backwards):
|
def find_next(self, backwards):
|
||||||
if not self.search_term:
|
if not self.search_term:
|
||||||
if self.state.last_search:
|
if self.last_search:
|
||||||
self.search_term = self.state.last_search
|
self.search_term = self.last_search
|
||||||
else:
|
else:
|
||||||
self.set_highlight(None)
|
self.set_highlight(None)
|
||||||
return
|
return
|
||||||
|
@ -164,10 +164,10 @@ class StatusBar(urwid.WidgetWrap):
|
|||||||
r.append("[")
|
r.append("[")
|
||||||
r.append(("heading_key", "i"))
|
r.append(("heading_key", "i"))
|
||||||
r.append(":%s]" % self.master.options.intercept)
|
r.append(":%s]" % self.master.options.intercept)
|
||||||
if self.master.state.filter_txt:
|
if self.master.options.filter:
|
||||||
r.append("[")
|
r.append("[")
|
||||||
r.append(("heading_key", "f"))
|
r.append(("heading_key", "f"))
|
||||||
r.append(":%s]" % self.master.state.filter_txt)
|
r.append(":%s]" % self.master.options.filter)
|
||||||
if self.master.options.stickycookie:
|
if self.master.options.stickycookie:
|
||||||
r.append("[")
|
r.append("[")
|
||||||
r.append(("heading_key", "t"))
|
r.append(("heading_key", "t"))
|
||||||
@ -194,7 +194,7 @@ class StatusBar(urwid.WidgetWrap):
|
|||||||
opts.append("killextra")
|
opts.append("killextra")
|
||||||
if self.master.options.no_upstream_cert:
|
if self.master.options.no_upstream_cert:
|
||||||
opts.append("no-upstream-cert")
|
opts.append("no-upstream-cert")
|
||||||
if self.master.state.follow_focus:
|
if self.master.options.follow_focus:
|
||||||
opts.append("following")
|
opts.append("following")
|
||||||
if self.master.options.stream_large_bodies:
|
if self.master.options.stream_large_bodies:
|
||||||
opts.append(
|
opts.append(
|
||||||
@ -224,11 +224,11 @@ class StatusBar(urwid.WidgetWrap):
|
|||||||
return r
|
return r
|
||||||
|
|
||||||
def redraw(self):
|
def redraw(self):
|
||||||
fc = self.master.state.flow_count()
|
fc = len(self.master.view)
|
||||||
if self.master.state.focus is None:
|
if self.master.view.focus.flow is None:
|
||||||
offset = 0
|
offset = 0
|
||||||
else:
|
else:
|
||||||
offset = min(self.master.state.focus + 1, fc)
|
offset = self.master.view.focus.index + 1
|
||||||
t = [
|
t = [
|
||||||
('heading', ("[%s/%s]" % (offset, fc)).ljust(9))
|
('heading', ("[%s/%s]" % (offset, fc)).ljust(9))
|
||||||
]
|
]
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
from mitmproxy.test import tflow
|
from mitmproxy.test import tflow
|
||||||
from mitmproxy.addons import view
|
from mitmproxy.addons import view
|
||||||
from mitmproxy import flowfilter
|
from mitmproxy import flowfilter
|
||||||
|
from mitmproxy import options
|
||||||
|
from mitmproxy.test import taddons
|
||||||
|
|
||||||
from .. import tutils
|
from .. import tutils
|
||||||
|
|
||||||
@ -31,6 +33,10 @@ def test_simple():
|
|||||||
assert list(v) == [f, f3, f2]
|
assert list(v) == [f, f3, f2]
|
||||||
assert len(v._store) == 3
|
assert len(v._store) == 3
|
||||||
|
|
||||||
|
v.clear()
|
||||||
|
assert len(v) == 0
|
||||||
|
assert len(v._store) == 0
|
||||||
|
|
||||||
|
|
||||||
def tft(*, method="get", start=0):
|
def tft(*, method="get", start=0):
|
||||||
f = tflow.tflow()
|
f = tflow.tflow()
|
||||||
@ -52,6 +58,14 @@ def test_filter():
|
|||||||
assert len(v._store) == 4
|
assert len(v._store) == 4
|
||||||
v.set_filter(None)
|
v.set_filter(None)
|
||||||
|
|
||||||
|
assert len(v) == 4
|
||||||
|
v[1].marked = True
|
||||||
|
v.toggle_marked()
|
||||||
|
assert len(v) == 1
|
||||||
|
assert v[0].marked
|
||||||
|
v.toggle_marked()
|
||||||
|
assert len(v) == 4
|
||||||
|
|
||||||
|
|
||||||
def test_order():
|
def test_order():
|
||||||
v = view.View()
|
v = view.View()
|
||||||
@ -236,31 +250,6 @@ def test_focus():
|
|||||||
assert f.index is None
|
assert f.index is None
|
||||||
|
|
||||||
|
|
||||||
def test_focus_nextprev():
|
|
||||||
v = view.View()
|
|
||||||
# Nops on an empty view
|
|
||||||
v.focus.next()
|
|
||||||
v.focus.prev()
|
|
||||||
|
|
||||||
# Nops on a single-flow view
|
|
||||||
v.add(tft(start=0))
|
|
||||||
assert v.focus.flow == v[0]
|
|
||||||
v.focus.next()
|
|
||||||
assert v.focus.flow == v[0]
|
|
||||||
v.focus.prev()
|
|
||||||
assert v.focus.flow == v[0]
|
|
||||||
|
|
||||||
v.add(tft(start=1))
|
|
||||||
v.focus.next()
|
|
||||||
assert v.focus.flow == v[1]
|
|
||||||
v.focus.next()
|
|
||||||
assert v.focus.flow == v[1]
|
|
||||||
v.focus.prev()
|
|
||||||
assert v.focus.flow == v[0]
|
|
||||||
v.focus.prev()
|
|
||||||
assert v.focus.flow == v[0]
|
|
||||||
|
|
||||||
|
|
||||||
def test_settings():
|
def test_settings():
|
||||||
v = view.View()
|
v = view.View()
|
||||||
f = tft()
|
f = tft()
|
||||||
@ -274,3 +263,16 @@ def test_settings():
|
|||||||
v.remove(f)
|
v.remove(f)
|
||||||
tutils.raises(KeyError, v.settings.__getitem__, f)
|
tutils.raises(KeyError, v.settings.__getitem__, f)
|
||||||
assert not v.settings.keys()
|
assert not v.settings.keys()
|
||||||
|
|
||||||
|
|
||||||
|
class Options(options.Options):
|
||||||
|
def __init__(self, *, filter=None, **kwargs):
|
||||||
|
self.filter = filter
|
||||||
|
super().__init__(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def test_configure():
|
||||||
|
v = view.View()
|
||||||
|
with taddons.context(options=Options()) as tctx:
|
||||||
|
tctx.configure(v, filter="~q")
|
||||||
|
tutils.raises("invalid interception filter", tctx.configure, v, filter="~~")
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
import gc
|
|
||||||
|
|
||||||
from mitmproxy.test import tflow
|
from mitmproxy.test import tflow
|
||||||
import mitmproxy.test.tutils
|
import mitmproxy.test.tutils
|
||||||
from mitmproxy.tools import console
|
from mitmproxy.tools import console
|
||||||
@ -9,93 +7,6 @@ from mitmproxy.tools.console import common
|
|||||||
from .. import mastertest
|
from .. import mastertest
|
||||||
|
|
||||||
|
|
||||||
class TestConsoleState:
|
|
||||||
|
|
||||||
def test_flow(self):
|
|
||||||
"""
|
|
||||||
normal flow:
|
|
||||||
|
|
||||||
connect -> request -> response
|
|
||||||
"""
|
|
||||||
c = console.master.ConsoleState()
|
|
||||||
f = self._add_request(c)
|
|
||||||
assert f in c.flows
|
|
||||||
assert c.get_focus() == (f, 0)
|
|
||||||
|
|
||||||
def test_focus(self):
|
|
||||||
"""
|
|
||||||
normal flow:
|
|
||||||
|
|
||||||
connect -> request -> response
|
|
||||||
"""
|
|
||||||
c = console.master.ConsoleState()
|
|
||||||
f = self._add_request(c)
|
|
||||||
|
|
||||||
assert c.get_focus() == (f, 0)
|
|
||||||
assert c.get_from_pos(0) == (f, 0)
|
|
||||||
assert c.get_from_pos(1) == (None, None)
|
|
||||||
assert c.get_next(0) == (None, None)
|
|
||||||
|
|
||||||
f2 = self._add_request(c)
|
|
||||||
assert c.get_focus() == (f, 0)
|
|
||||||
assert c.get_next(0) == (f2, 1)
|
|
||||||
assert c.get_prev(1) == (f, 0)
|
|
||||||
assert c.get_next(1) == (None, None)
|
|
||||||
|
|
||||||
c.set_focus(0)
|
|
||||||
assert c.get_focus() == (f, 0)
|
|
||||||
c.set_focus(-1)
|
|
||||||
assert c.get_focus() == (f, 0)
|
|
||||||
c.set_focus(2)
|
|
||||||
assert c.get_focus() == (f2, 1)
|
|
||||||
|
|
||||||
c.delete_flow(f2)
|
|
||||||
assert c.get_focus() == (f, 0)
|
|
||||||
c.delete_flow(f)
|
|
||||||
assert c.get_focus() == (None, None)
|
|
||||||
|
|
||||||
def _add_request(self, state):
|
|
||||||
f = tflow.tflow()
|
|
||||||
return state.add_flow(f)
|
|
||||||
|
|
||||||
def _add_response(self, state):
|
|
||||||
f = self._add_request(state)
|
|
||||||
f.response = mitmproxy.test.tutils.tresp()
|
|
||||||
state.update_flow(f)
|
|
||||||
|
|
||||||
def test_add_response(self):
|
|
||||||
c = console.master.ConsoleState()
|
|
||||||
f = self._add_request(c)
|
|
||||||
f.response = mitmproxy.test.tutils.tresp()
|
|
||||||
c.focus = None
|
|
||||||
c.update_flow(f)
|
|
||||||
|
|
||||||
def test_focus_view(self):
|
|
||||||
c = console.master.ConsoleState()
|
|
||||||
self._add_request(c)
|
|
||||||
self._add_response(c)
|
|
||||||
self._add_request(c)
|
|
||||||
self._add_response(c)
|
|
||||||
self._add_request(c)
|
|
||||||
self._add_response(c)
|
|
||||||
assert not c.set_view_filter("~s")
|
|
||||||
assert len(c.view) == 3
|
|
||||||
assert c.focus == 0
|
|
||||||
|
|
||||||
def test_settings(self):
|
|
||||||
c = console.master.ConsoleState()
|
|
||||||
f = self._add_request(c)
|
|
||||||
c.add_flow_setting(f, "foo", "bar")
|
|
||||||
assert c.get_flow_setting(f, "foo") == "bar"
|
|
||||||
assert c.get_flow_setting(f, "oink") is None
|
|
||||||
assert c.get_flow_setting(f, "oink", "foo") == "foo"
|
|
||||||
assert len(c.flowsettings) == 1
|
|
||||||
c.delete_flow(f)
|
|
||||||
del f
|
|
||||||
gc.collect()
|
|
||||||
assert len(c.flowsettings) == 0
|
|
||||||
|
|
||||||
|
|
||||||
def test_format_keyvals():
|
def test_format_keyvals():
|
||||||
assert common.format_keyvals(
|
assert common.format_keyvals(
|
||||||
[
|
[
|
||||||
@ -123,17 +34,17 @@ class TestMaster(mastertest.MasterTest):
|
|||||||
m = self.mkmaster()
|
m = self.mkmaster()
|
||||||
for i in (1, 2, 3):
|
for i in (1, 2, 3):
|
||||||
self.dummy_cycle(m, 1, b"")
|
self.dummy_cycle(m, 1, b"")
|
||||||
assert len(m.state.flows) == i
|
assert len(m.view) == i
|
||||||
|
|
||||||
def test_intercept(self):
|
def test_intercept(self):
|
||||||
"""regression test for https://github.com/mitmproxy/mitmproxy/issues/1605"""
|
"""regression test for https://github.com/mitmproxy/mitmproxy/issues/1605"""
|
||||||
m = self.mkmaster(intercept="~b bar")
|
m = self.mkmaster(intercept="~b bar")
|
||||||
f = tflow.tflow(req=mitmproxy.test.tutils.treq(content=b"foo"))
|
f = tflow.tflow(req=mitmproxy.test.tutils.treq(content=b"foo"))
|
||||||
m.request(f)
|
m.request(f)
|
||||||
assert not m.state.flows[0].intercepted
|
assert not m.view[0].intercepted
|
||||||
f = tflow.tflow(req=mitmproxy.test.tutils.treq(content=b"bar"))
|
f = tflow.tflow(req=mitmproxy.test.tutils.treq(content=b"bar"))
|
||||||
m.request(f)
|
m.request(f)
|
||||||
assert m.state.flows[1].intercepted
|
assert m.view[1].intercepted
|
||||||
f = tflow.tflow(resp=mitmproxy.test.tutils.tresp(content=b"bar"))
|
f = tflow.tflow(resp=mitmproxy.test.tutils.tresp(content=b"bar"))
|
||||||
m.request(f)
|
m.request(f)
|
||||||
assert m.state.flows[2].intercepted
|
assert m.view[2].intercepted
|
||||||
|
Loading…
Reference in New Issue
Block a user