aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAldo Cortesi <aldo@corte.si>2017-03-20 12:39:49 +1300
committerGitHub <noreply@github.com>2017-03-20 12:39:49 +1300
commit0c0c0d38cc65b4b1cecbe82d8d2b558ed3c62994 (patch)
treed49c3621a0b80e4423e054e127a4d08d5d2a7ae1
parent92e33589159ee94df831fc0f0b2084854a6c44ae (diff)
parentb98ce71770d22d4b80e83f56b74dc710405cf535 (diff)
downloadmitmproxy-0c0c0d38cc65b4b1cecbe82d8d2b558ed3c62994.tar.gz
mitmproxy-0c0c0d38cc65b4b1cecbe82d8d2b558ed3c62994.tar.bz2
mitmproxy-0c0c0d38cc65b4b1cecbe82d8d2b558ed3c62994.zip
Merge pull request #2186 from cortesi/tighten
Tighten some options-related functionality
-rw-r--r--mitmproxy/addons/dumper.py8
-rw-r--r--mitmproxy/addons/streamfile.py8
-rw-r--r--mitmproxy/addons/view.py23
-rw-r--r--mitmproxy/options.py18
-rw-r--r--mitmproxy/optmanager.py2
-rw-r--r--mitmproxy/tools/cmdline.py6
-rw-r--r--mitmproxy/tools/console/flowlist.py4
-rw-r--r--mitmproxy/tools/console/flowview.py28
-rw-r--r--mitmproxy/tools/console/grideditor/editors.py5
-rw-r--r--mitmproxy/tools/console/options.py14
-rw-r--r--mitmproxy/tools/console/statusbar.py6
-rw-r--r--mitmproxy/tools/main.py20
-rw-r--r--mitmproxy/utils/sliding_window.py4
-rw-r--r--test/mitmproxy/addons/test_dumper.py6
-rw-r--r--test/mitmproxy/addons/test_streamfile.py8
-rw-r--r--test/mitmproxy/addons/test_view.py8
-rw-r--r--test/mitmproxy/test_optmanager.py8
-rw-r--r--test/mitmproxy/tools/test_dump.py2
18 files changed, 103 insertions, 75 deletions
diff --git a/mitmproxy/addons/dumper.py b/mitmproxy/addons/dumper.py
index 222f1167..ca0d32d3 100644
--- a/mitmproxy/addons/dumper.py
+++ b/mitmproxy/addons/dumper.py
@@ -35,12 +35,12 @@ class Dumper:
self.default_contentview = "auto" # type: str
def configure(self, options, updated):
- if "filtstr" in updated:
- if options.filtstr:
- self.filter = flowfilter.parse(options.filtstr)
+ if "view_filter" in updated:
+ if options.view_filter:
+ self.filter = flowfilter.parse(options.view_filter)
if not self.filter:
raise exceptions.OptionsError(
- "Invalid filter expression: %s" % options.filtstr
+ "Invalid filter expression: %s" % options.view_filter
)
else:
self.filter = None
diff --git a/mitmproxy/addons/streamfile.py b/mitmproxy/addons/streamfile.py
index 624297f2..183d2036 100644
--- a/mitmproxy/addons/streamfile.py
+++ b/mitmproxy/addons/streamfile.py
@@ -22,12 +22,12 @@ class StreamFile:
def configure(self, options, updated):
# We're already streaming - stop the previous stream and restart
- if "filtstr" in updated:
- if options.filtstr:
- self.filt = flowfilter.parse(options.filtstr)
+ if "streamfile_filter" in updated:
+ if options.streamfile_filter:
+ self.filt = flowfilter.parse(options.streamfile_filter)
if not self.filt:
raise exceptions.OptionsError(
- "Invalid filter specification: %s" % options.filtstr
+ "Invalid filter specification: %s" % options.streamfile_filter
)
else:
self.filt = None
diff --git a/mitmproxy/addons/view.py b/mitmproxy/addons/view.py
index 2218327c..1b8a30e4 100644
--- a/mitmproxy/addons/view.py
+++ b/mitmproxy/addons/view.py
@@ -109,7 +109,7 @@ class View(collections.Sequence):
self.default_order = OrderRequestStart(self)
self.orders = dict(
- time = self.default_order,
+ time = OrderRequestStart(self),
method = OrderRequestMethod(self),
url = OrderRequestURL(self),
size = OrderKeySize(self),
@@ -300,24 +300,21 @@ class View(collections.Sequence):
# Event handlers
def configure(self, opts, updated):
- if "filter" in updated:
+ if "view_filter" in updated:
filt = None
- if opts.filter:
- filt = flowfilter.parse(opts.filter)
+ if opts.view_filter:
+ filt = flowfilter.parse(opts.view_filter)
if not filt:
raise exceptions.OptionsError(
- "Invalid interception filter: %s" % opts.filter
+ "Invalid interception filter: %s" % opts.view_filter
)
self.set_filter(filt)
if "console_order" in updated:
- if opts.console_order is None:
- self.set_order(self.default_order)
- else:
- if opts.console_order not in self.orders:
- raise exceptions.OptionsError(
- "Unknown flow order: %s" % opts.console_order
- )
- self.set_order(self.orders[opts.console_order])
+ if opts.console_order not in self.orders:
+ raise exceptions.OptionsError(
+ "Unknown flow order: %s" % opts.console_order
+ )
+ self.set_order(self.orders[opts.console_order])
if "console_order_reversed" in updated:
self.set_reversed(opts.console_order_reversed)
if "console_focus_follow" in updated:
diff --git a/mitmproxy/options.py b/mitmproxy/options.py
index 9232378f..8f8c1484 100644
--- a/mitmproxy/options.py
+++ b/mitmproxy/options.py
@@ -1,6 +1,7 @@
from typing import Optional, Sequence
from mitmproxy import optmanager
+from mitmproxy import contentviews
from mitmproxy.net import tcp
# We redefine these here for now to avoid importing Urwid-related guff on
@@ -154,13 +155,18 @@ class Options(optmanager.OptManager):
)
self.add_option(
"default_contentview", str, "auto",
- "The default content view mode."
+ "The default content view mode.",
+ choices = [i.name.lower() for i in contentviews.views]
)
self.add_option(
"streamfile", Optional[str], None,
"Write flows to file. Prefix path with + to append."
)
self.add_option(
+ "streamfile_filter", Optional[str], None,
+ "Filter which flows are written to file."
+ )
+ self.add_option(
"server_replay_ignore_content", bool, False,
"Ignore request's content while searching for a saved flow to replay."
)
@@ -386,7 +392,7 @@ class Options(optmanager.OptManager):
"Console mouse interaction."
)
self.add_option(
- "console_order", Optional[str], None,
+ "console_order", str, "time",
"Flow sort order.",
choices=view_orders,
)
@@ -396,8 +402,8 @@ class Options(optmanager.OptManager):
)
self.add_option(
- "filter", Optional[str], None,
- "Filter view expression."
+ "view_filter", Optional[str], None,
+ "Limit which flows are displayed."
)
# Web options
@@ -420,10 +426,6 @@ class Options(optmanager.OptManager):
# Dump options
self.add_option(
- "filtstr", Optional[str], None,
- "The filter string for mitmdump."
- )
- self.add_option(
"flow_detail", int, 1,
"Flow detail display level."
)
diff --git a/mitmproxy/optmanager.py b/mitmproxy/optmanager.py
index f1d6461d..c58bc7d0 100644
--- a/mitmproxy/optmanager.py
+++ b/mitmproxy/optmanager.py
@@ -196,7 +196,7 @@ class OptManager:
unknown[k] = v
updated = set(known.keys())
if updated:
- with self.rollback(updated):
+ with self.rollback(updated, reraise=True):
for k, v in known.items():
self._options[k].set(v)
self.changed.send(self, updated=updated)
diff --git a/mitmproxy/tools/cmdline.py b/mitmproxy/tools/cmdline.py
index da091c12..fbdbce52 100644
--- a/mitmproxy/tools/cmdline.py
+++ b/mitmproxy/tools/cmdline.py
@@ -109,7 +109,7 @@ def mitmproxy(opts):
"See help in mitmproxy for filter expression syntax."
)
opts.make_parser(group, "intercept", metavar="FILTER")
- opts.make_parser(group, "filter", metavar="FILTER")
+ opts.make_parser(group, "view_filter", metavar="FILTER")
return parser
@@ -122,8 +122,8 @@ def mitmdump(opts):
'filter_args',
nargs="...",
help="""
- Filter view expression, used to only show flows that match a certain
- filter. See help in mitmproxy for filter expression syntax.
+ Filter expression, equivalent to setting both the view_filter
+ and streamfile_filter options.
"""
)
return parser
diff --git a/mitmproxy/tools/console/flowlist.py b/mitmproxy/tools/console/flowlist.py
index 5fe86975..04052ec8 100644
--- a/mitmproxy/tools/console/flowlist.py
+++ b/mitmproxy/tools/console/flowlist.py
@@ -366,8 +366,8 @@ class FlowListBox(urwid.ListBox):
elif key == "f":
signals.status_prompt.send(
prompt = "Filter View",
- text = self.master.options.filter,
- callback = self.master.options.setter("filter")
+ text = self.master.options.view_filter,
+ callback = self.master.options.setter("view_filter")
)
elif key == "L":
signals.status_prompt_path.send(
diff --git a/mitmproxy/tools/console/flowview.py b/mitmproxy/tools/console/flowview.py
index 90cca1c5..ba41c947 100644
--- a/mitmproxy/tools/console/flowview.py
+++ b/mitmproxy/tools/console/flowview.py
@@ -15,6 +15,7 @@ from mitmproxy.net.http import status_codes
from mitmproxy.tools.console import common
from mitmproxy.tools.console import flowdetailview
from mitmproxy.tools.console import grideditor
+from mitmproxy.tools.console import overlay
from mitmproxy.tools.console import searchable
from mitmproxy.tools.console import signals
from mitmproxy.tools.console import tabs
@@ -237,11 +238,10 @@ class FlowView(tabs.Tabs):
return description, text_objects
def viewmode_get(self):
- override = self.view.settings[self.flow].get(
+ return self.view.settings[self.flow].get(
(self.tab_offset, "prettyview"),
- None
+ self.master.options.default_contentview
)
- return self.master.options.default_contentview if override is None else override
def conn_text(self, conn):
if conn:
@@ -483,11 +483,8 @@ class FlowView(tabs.Tabs):
return self._view_nextprev_flow(self.view.index(flow) - 1, flow)
def change_this_display_mode(self, t):
- view = contentviews.get_by_shortcut(t)
- if view:
- self.view.settings[self.flow][(self.tab_offset, "prettyview")] = view.name
- else:
- self.view.settings[self.flow][(self.tab_offset, "prettyview")] = None
+ view = contentviews.get(t)
+ self.view.settings[self.flow][(self.tab_offset, "prettyview")] = view.name.lower()
signals.flow_change.send(self, flow=self.flow)
def keypress(self, size, key):
@@ -607,13 +604,14 @@ class FlowView(tabs.Tabs):
signals.flow_change.send(self, flow = self.flow)
signals.status_message.send(message="Loading all body data...")
elif key == "m":
- p = list(contentviews.view_prompts)
- p.insert(0, ("Clear", "C"))
- signals.status_prompt_onekey.send(
- self,
- prompt = "Display mode",
- keys = p,
- callback = self.change_this_display_mode
+ opts = [i.name.lower() for i in contentviews.views]
+ self.master.overlay(
+ overlay.Chooser(
+ "display mode",
+ opts,
+ self.viewmode_get(),
+ self.change_this_display_mode
+ )
)
elif key == "E":
if self.tab_offset == TAB_REQ:
diff --git a/mitmproxy/tools/console/grideditor/editors.py b/mitmproxy/tools/console/grideditor/editors.py
index 39e51b2b..313495e4 100644
--- a/mitmproxy/tools/console/grideditor/editors.py
+++ b/mitmproxy/tools/console/grideditor/editors.py
@@ -258,7 +258,10 @@ class OptionsEditor(base.GridEditor):
super().__init__(master, [[i] for i in vals], self.callback)
def callback(self, vals):
- setattr(self.master.options, self.name, [i[0] for i in vals])
+ try:
+ setattr(self.master.options, self.name, [i[0] for i in vals])
+ except exceptions.OptionsError as v:
+ signals.status_message.send(message=str(v))
def is_error(self, col, val):
pass
diff --git a/mitmproxy/tools/console/options.py b/mitmproxy/tools/console/options.py
index f38550f9..56d22715 100644
--- a/mitmproxy/tools/console/options.py
+++ b/mitmproxy/tools/console/options.py
@@ -30,6 +30,7 @@ def _mkhelp():
keys = [
("enter", "edit option"),
("D", "reset all to defaults"),
+ ("d", "reset this option to default"),
("w", "save options"),
]
text.extend(common.format_keyvals(keys, key="key", val="text", indent=4))
@@ -107,6 +108,7 @@ class OptionItem(urwid.WidgetWrap):
def keypress(self, size, key):
if self.editing:
self._w[1].keypress(size, key)
+ return
return key
@@ -184,15 +186,21 @@ class OptionsList(urwid.ListBox):
v = self.walker.get_edit_text()
try:
d = self.master.options.parse_setval(foc.opt.name, v)
+ self.master.options.update(**{foc.opt.name: d})
except exceptions.OptionsError as v:
signals.status_message.send(message=str(v))
- else:
- self.master.options.update(**{foc.opt.name: d})
self.walker.stop_editing()
elif key == "esc":
self.walker.stop_editing()
else:
- if key == "g":
+ if key == "d":
+ foc, idx = self.get_focus()
+ setattr(
+ self.master.options,
+ foc.opt.name,
+ self.master.options.default(foc.opt.name)
+ )
+ elif key == "g":
self.set_focus(0)
self.walker._modified()
elif key == "G":
diff --git a/mitmproxy/tools/console/statusbar.py b/mitmproxy/tools/console/statusbar.py
index 3f18bbb3..c7132864 100644
--- a/mitmproxy/tools/console/statusbar.py
+++ b/mitmproxy/tools/console/statusbar.py
@@ -191,10 +191,10 @@ class StatusBar(urwid.WidgetWrap):
r.append("[")
r.append(("heading_key", "i"))
r.append(":%s]" % self.master.options.intercept)
- if self.master.options.filter:
+ if self.master.options.view_filter:
r.append("[")
r.append(("heading_key", "f"))
- r.append(":%s]" % self.master.options.filter)
+ r.append(":%s]" % self.master.options.view_filter)
if self.master.options.stickycookie:
r.append("[")
r.append(("heading_key", "t"))
@@ -207,7 +207,7 @@ class StatusBar(urwid.WidgetWrap):
r.append("[")
r.append(("heading_key", "M"))
r.append(":%s]" % self.master.options.default_contentview)
- if self.master.options.console_order:
+ if self.master.options.has_changed("console_order"):
r.append("[")
r.append(("heading_key", "o"))
r.append(":%s]" % self.master.options.console_order)
diff --git a/mitmproxy/tools/main.py b/mitmproxy/tools/main.py
index b321e8f8..6db232fc 100644
--- a/mitmproxy/tools/main.py
+++ b/mitmproxy/tools/main.py
@@ -60,7 +60,11 @@ def process_options(parser, opts, args):
return server.DummyServer(pconf)
-def run(MasterKlass, args): # pragma: no cover
+def run(MasterKlass, args, extra=None): # pragma: no cover
+ """
+ extra: Extra argument processing callable which returns a dict of
+ options.
+ """
version_check.check_pyopenssl_version()
debug.register_info_dumpers()
@@ -80,6 +84,8 @@ def run(MasterKlass, args): # pragma: no cover
print(optmanager.dump_defaults(opts))
sys.exit(0)
opts.set(*args.setoptions)
+ if extra:
+ opts.update(**extra(args))
def cleankill(*args, **kwargs):
master.shutdown()
@@ -107,7 +113,17 @@ def mitmproxy(args=None): # pragma: no cover
def mitmdump(args=None): # pragma: no cover
from mitmproxy.tools import dump
- m = run(dump.DumpMaster, args)
+
+ def extra(args):
+ if args.filter_args:
+ v = " ".join(args.filter_args)
+ return dict(
+ view_filter = v,
+ streamfile_filter = v,
+ )
+ return {}
+
+ m = run(dump.DumpMaster, args, extra)
if m and m.errorcheck.has_errored:
sys.exit(1)
diff --git a/mitmproxy/utils/sliding_window.py b/mitmproxy/utils/sliding_window.py
index 4714b8e3..0a65f5e4 100644
--- a/mitmproxy/utils/sliding_window.py
+++ b/mitmproxy/utils/sliding_window.py
@@ -1,10 +1,10 @@
import itertools
-from typing import TypeVar, Iterator, Tuple, Optional
+from typing import TypeVar, Iterable, Iterator, Tuple, Optional
T = TypeVar('T')
-def window(iterator: Iterator[T], behind: int = 0, ahead: int = 0) -> Iterator[Tuple[Optional[T]]]:
+def window(iterator: Iterable[T], behind: int = 0, ahead: int = 0) -> Iterator[Tuple[Optional[T], ...]]:
"""
Sliding window for an iterator.
diff --git a/test/mitmproxy/addons/test_dumper.py b/test/mitmproxy/addons/test_dumper.py
index fbcc4d16..d2cefe79 100644
--- a/test/mitmproxy/addons/test_dumper.py
+++ b/test/mitmproxy/addons/test_dumper.py
@@ -16,7 +16,7 @@ from mitmproxy import options
def test_configure():
d = dumper.Dumper()
with taddons.context(options=options.Options()) as ctx:
- ctx.configure(d, filtstr="~b foo")
+ ctx.configure(d, view_filter="~b foo")
assert d.filter
f = tflow.tflow(resp=True)
@@ -24,10 +24,10 @@ def test_configure():
f.response.content = b"foo"
assert d.match(f)
- ctx.configure(d, filtstr=None)
+ ctx.configure(d, view_filter=None)
assert not d.filter
with pytest.raises(exceptions.OptionsError):
- ctx.configure(d, filtstr="~~")
+ ctx.configure(d, view_filter="~~")
assert not d.filter
diff --git a/test/mitmproxy/addons/test_streamfile.py b/test/mitmproxy/addons/test_streamfile.py
index 3f78521c..bcb27c79 100644
--- a/test/mitmproxy/addons/test_streamfile.py
+++ b/test/mitmproxy/addons/test_streamfile.py
@@ -15,10 +15,12 @@ def test_configure(tmpdir):
with pytest.raises(exceptions.OptionsError):
tctx.configure(sa, streamfile=str(tmpdir))
with pytest.raises(Exception, match="Invalid filter"):
- tctx.configure(sa, streamfile=str(tmpdir.join("foo")), filtstr="~~")
- tctx.configure(sa, filtstr="foo")
+ tctx.configure(
+ sa, streamfile=str(tmpdir.join("foo")), streamfile_filter="~~"
+ )
+ tctx.configure(sa, streamfile_filter="foo")
assert sa.filt
- tctx.configure(sa, filtstr=None)
+ tctx.configure(sa, streamfile_filter=None)
assert not sa.filt
diff --git a/test/mitmproxy/addons/test_view.py b/test/mitmproxy/addons/test_view.py
index b7842314..7fa3819e 100644
--- a/test/mitmproxy/addons/test_view.py
+++ b/test/mitmproxy/addons/test_view.py
@@ -264,7 +264,7 @@ def test_signals():
def test_focus_follow():
v = view.View()
with taddons.context(options=options.Options()) as tctx:
- tctx.configure(v, console_focus_follow=True, filter="~m get")
+ tctx.configure(v, console_focus_follow=True, view_filter="~m get")
v.add(tft(start=5))
assert v.focus.index == 0
@@ -378,9 +378,9 @@ def test_settings():
def test_configure():
v = view.View()
with taddons.context(options=options.Options()) as tctx:
- tctx.configure(v, filter="~q")
+ tctx.configure(v, view_filter="~q")
with pytest.raises(Exception, match="Invalid interception filter"):
- tctx.configure(v, filter="~~")
+ tctx.configure(v, view_filter="~~")
tctx.configure(v, console_order="method")
with pytest.raises(Exception, match="Unknown flow order"):
@@ -388,7 +388,5 @@ def test_configure():
tctx.configure(v, console_order_reversed=True)
- tctx.configure(v, console_order=None)
-
tctx.configure(v, console_focus_follow=True)
assert v.focus_follow
diff --git a/test/mitmproxy/test_optmanager.py b/test/mitmproxy/test_optmanager.py
index ef5ebd27..01636640 100644
--- a/test/mitmproxy/test_optmanager.py
+++ b/test/mitmproxy/test_optmanager.py
@@ -210,8 +210,12 @@ def test_rollback():
o.errored.connect(errsub)
assert o.one is None
- o.one = 10
- o.bool = True
+ with pytest.raises(exceptions.OptionsError):
+ o.one = 10
+ assert o.one is None
+ with pytest.raises(exceptions.OptionsError):
+ o.bool = True
+ assert o.bool is False
assert isinstance(recerr[0]["exc"], exceptions.OptionsError)
assert o.one is None
assert o.bool is False
diff --git a/test/mitmproxy/tools/test_dump.py b/test/mitmproxy/tools/test_dump.py
index 8e2fa5b2..69a76d2e 100644
--- a/test/mitmproxy/tools/test_dump.py
+++ b/test/mitmproxy/tools/test_dump.py
@@ -12,7 +12,7 @@ from .. import tservers
class TestDumpMaster(tservers.MasterTest):
def mkmaster(self, flt, **opts):
- o = options.Options(filtstr=flt, verbosity=-1, flow_detail=0, **opts)
+ o = options.Options(view_filter=flt, verbosity=-1, flow_detail=0, **opts)
m = dump.DumpMaster(o, proxy.DummyServer(), with_termlog=False, with_dumper=False)
return m