From ac3b0d69cc29b5469f6b4cc55af528f6266d42cf Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Tue, 7 Mar 2017 14:27:50 +1300 Subject: Add the --set option to set options directly The --set option is a universal flag for setting options. Some examples: Turn on a boolean: mitmdump --set onboarding=false Add a value to a sequence: mitumdupm --set setheaders=/foo/bar/voing Zero a sequence: mitumdupm --set setheaders --- mitmproxy/optmanager.py | 39 ++++++++++++++++++++++++++++++++++++++ mitmproxy/tools/cmdline.py | 24 +++++++++++++++++------ mitmproxy/tools/main.py | 3 +++ test/mitmproxy/test_optmanager.py | 40 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 100 insertions(+), 6 deletions(-) diff --git a/mitmproxy/optmanager.py b/mitmproxy/optmanager.py index beb9084c..eb56ef2d 100644 --- a/mitmproxy/optmanager.py +++ b/mitmproxy/optmanager.py @@ -323,6 +323,45 @@ class OptManager: options=options ) + def set(self, spec): + parts = spec.split("=", maxsplit=1) + if len(parts) == 1: + optname, optval = parts[0], None + else: + optname, optval = parts[0], parts[1] + o = self._options[optname] + + if o.typespec in (str, typing.Optional[str]): + setattr(self, optname, optval) + elif o.typespec in (int, typing.Optional[int]): + if optval: + try: + optval = int(optval) + except ValueError: + raise exceptions.OptionsError("Not an integer: %s" % optval) + setattr(self, optname, optval) + elif o.typespec == bool: + if not optval or optval == "true": + v = True + elif optval == "false": + v = False + else: + raise exceptions.OptionsError( + "Boolean must be \"true\", \"false\", or have the value " "omitted (a synonym for \"true\")." + ) + setattr(self, optname, v) + elif o.typespec == typing.Sequence[str]: + if not optval: + setattr(self, optname, []) + else: + setattr( + self, + optname, + getattr(self, optname) + [optval] + ) + else: + raise ValueError("Unsupported option type: %s", o.typespec) + def make_parser(self, parser, optname, metavar=None): o = self._options[optname] f = optname.replace("_", "-") diff --git a/mitmproxy/tools/cmdline.py b/mitmproxy/tools/cmdline.py index 7b0da34f..ea77acfd 100644 --- a/mitmproxy/tools/cmdline.py +++ b/mitmproxy/tools/cmdline.py @@ -25,6 +25,24 @@ def common_options(parser, opts): action='store_true', help="Dump all options", ) + parser.add_argument( + "--conf", + type=str, dest="conf", default=CONFIG_PATH, + metavar="PATH", + help="Read options from a configuration file" + ) + parser.add_argument( + "--set", + type=str, dest="setoptions", default=[], + action="append", + metavar="option[=value]", + help=""" + Set an option. When the value is omitted, booleans are set to true, + strings and integers are set to None (if permitted), and sequences + are emptied. + """ + ) + parser.add_argument( "-q", "--quiet", action="store_true", dest="quiet", @@ -35,12 +53,6 @@ def common_options(parser, opts): action="store_const", dest="verbose", const=3, help="Increase log verbosity." ) - parser.add_argument( - "--conf", - type=str, dest="conf", default=CONFIG_PATH, - metavar="PATH", - help="Configuration file" - ) # Basic options opts.make_parser(parser, "mode") diff --git a/mitmproxy/tools/main.py b/mitmproxy/tools/main.py index 5c58d995..7c1e7b32 100644 --- a/mitmproxy/tools/main.py +++ b/mitmproxy/tools/main.py @@ -45,6 +45,9 @@ def process_options(parser, opts, args): if args.quiet: args.flow_detail = 0 + for i in args.setoptions: + opts.set(i) + adict = {} for n in dir(args): if n in opts: diff --git a/test/mitmproxy/test_optmanager.py b/test/mitmproxy/test_optmanager.py index 010fc339..9311e82d 100644 --- a/test/mitmproxy/test_optmanager.py +++ b/test/mitmproxy/test_optmanager.py @@ -292,8 +292,10 @@ class TTypes(optmanager.OptManager): def __init__(self): super().__init__() self.add_option("str", "str", str) + self.add_option("optstr", "optstr", typing.Optional[str]) self.add_option("bool", False, bool) self.add_option("int", 0, int) + self.add_option("optint", 0, typing.Optional[int]) self.add_option("seqstr", [], typing.Sequence[str]) self.add_option("unknown", 0.0, float) @@ -307,3 +309,41 @@ def test_make_parser(): opts.make_parser(parser, "seqstr") with pytest.raises(ValueError): opts.make_parser(parser, "unknown") + + +def test_set(): + opts = TTypes() + + opts.set("str=foo") + assert opts.str == "foo" + with pytest.raises(TypeError): + opts.set("str") + + opts.set("optstr=foo") + assert opts.optstr == "foo" + opts.set("optstr") + assert opts.optstr is None + + opts.set("bool=false") + assert opts.bool is False + opts.set("bool") + assert opts.bool is True + opts.set("bool=true") + assert opts.bool is True + with pytest.raises(exceptions.OptionsError): + opts.set("bool=wobble") + + opts.set("int=1") + assert opts.int == 1 + with pytest.raises(exceptions.OptionsError): + opts.set("int=wobble") + opts.set("optint") + assert opts.optint is None + + assert opts.seqstr == [] + opts.set("seqstr=foo") + assert opts.seqstr == ["foo"] + opts.set("seqstr=bar") + assert opts.seqstr == ["foo", "bar"] + opts.set("seqstr") + assert opts.seqstr == [] -- cgit v1.2.3