aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMaximilian Hils <git@maximilianhils.com>2019-11-18 22:03:51 +0100
committerMaximilian Hils <git@maximilianhils.com>2019-11-18 22:03:51 +0100
commit74f5fa6a7736f116416c242b159e6b0525e6fe5b (patch)
tree0c90e441aea082e91ee9b864f3c98363e1232927
parent7bf06f8ae04697305731ec89a43ebea6da4376b8 (diff)
downloadmitmproxy-74f5fa6a7736f116416c242b159e6b0525e6fe5b.tar.gz
mitmproxy-74f5fa6a7736f116416c242b159e6b0525e6fe5b.tar.bz2
mitmproxy-74f5fa6a7736f116416c242b159e6b0525e6fe5b.zip
wip
-rw-r--r--mitmproxy/addons/core.py17
-rw-r--r--mitmproxy/addons/view.py26
-rw-r--r--mitmproxy/command.py27
-rw-r--r--mitmproxy/tools/console/commander/commander.py8
-rw-r--r--mitmproxy/tools/console/commands.py2
-rw-r--r--mitmproxy/tools/console/consoleaddons.py11
-rw-r--r--test/mitmproxy/tools/console/test_commander.py4
7 files changed, 55 insertions, 40 deletions
diff --git a/mitmproxy/addons/core.py b/mitmproxy/addons/core.py
index 1fbeb1e0..55e2e129 100644
--- a/mitmproxy/addons/core.py
+++ b/mitmproxy/addons/core.py
@@ -83,15 +83,15 @@ class Core:
)
@command.command("set")
- def set(self, *options: str) -> None:
+ def set(self, option: str, *value: str) -> None:
"""
- Set an option of the form "key[=value]". When the value is omitted,
- booleans are set to true, strings and integers are set to None (if
- permitted), and sequences are emptied. Boolean values can be true,
- false or toggle. If multiple specs are passed, they are joined
- into one separated by spaces.
+ 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. Boolean values can be true, false or toggle.
+ Multiple values are concatenated with a single space.
"""
- strspec = " ".join(options)
+ value = " ".join(value)
+ strspec = f"{option}={value}"
try:
ctx.options.set(strspec)
except exceptions.OptionsError as e:
@@ -168,8 +168,7 @@ class Core:
"reason",
]
- @command.command(
- "flow.set")
+ @command.command("flow.set")
@command.argument("attr", type=mitmproxy.types.Choice("flow.set.options"))
def flow_set(
self,
diff --git a/mitmproxy/addons/view.py b/mitmproxy/addons/view.py
index c57c34c8..1d57d781 100644
--- a/mitmproxy/addons/view.py
+++ b/mitmproxy/addons/view.py
@@ -298,16 +298,16 @@ class View(collections.abc.Sequence):
# Filter
@command.command("view.filter.set")
- def set_filter_cmd(self, filtstr: str) -> None:
+ def set_filter_cmd(self, filter_expr: str) -> None:
"""
Sets the current view filter.
"""
filt = None
- if filtstr:
- filt = flowfilter.parse(filtstr)
+ if filter_expr:
+ filt = flowfilter.parse(filter_expr)
if not filt:
raise exceptions.CommandError(
- "Invalid interception filter: %s" % filtstr
+ "Invalid interception filter: %s" % filter_expr
)
self.set_filter(filt)
@@ -412,26 +412,26 @@ class View(collections.abc.Sequence):
ctx.log.alert("Removed %s flows" % len(flows))
@command.command("view.flows.resolve")
- def resolve(self, flowspec: str) -> typing.Sequence[mitmproxy.flow.Flow]:
+ def resolve(self, flow_spec: str) -> typing.Sequence[mitmproxy.flow.Flow]:
"""
Resolve a flow list specification to an actual list of flows.
"""
- if flowspec == "@all":
+ if flow_spec == "@all":
return [i for i in self._store.values()]
- if flowspec == "@focus":
+ if flow_spec == "@focus":
return [self.focus.flow] if self.focus.flow else []
- elif flowspec == "@shown":
+ elif flow_spec == "@shown":
return [i for i in self]
- elif flowspec == "@hidden":
+ elif flow_spec == "@hidden":
return [i for i in self._store.values() if i not in self._view]
- elif flowspec == "@marked":
+ elif flow_spec == "@marked":
return [i for i in self._store.values() if i.marked]
- elif flowspec == "@unmarked":
+ elif flow_spec == "@unmarked":
return [i for i in self._store.values() if not i.marked]
else:
- filt = flowfilter.parse(flowspec)
+ filt = flowfilter.parse(flow_spec)
if not filt:
- raise exceptions.CommandError("Invalid flow filter: %s" % flowspec)
+ raise exceptions.CommandError("Invalid flow filter: %s" % flow_spec)
return [i for i in self._store.values() if filt(i)]
@command.command("view.flows.create")
diff --git a/mitmproxy/command.py b/mitmproxy/command.py
index 00238f46..7203fe42 100644
--- a/mitmproxy/command.py
+++ b/mitmproxy/command.py
@@ -3,6 +3,7 @@
"""
import functools
import inspect
+import re
import sys
import textwrap
import types
@@ -284,13 +285,27 @@ class CommandManager:
def unquote(x: str) -> str:
- if x.startswith("'") and x.endswith("'"):
- return x[1:-1]
- if x.startswith('"') and x.endswith('"'):
- return x[1:-1]
+ quoted = (
+ (x.startswith('"') and x.endswith('"'))
+ or
+ (x.startswith("'") and x.endswith("'"))
+ )
+ if quoted:
+ x = x[1:-1]
+ # not sure if this is the right place, but pypyarsing doesn't process escape sequences.
+ x = re.sub(r"\\(.)", r"\g<1>", x)
+ return x
return x
+def quote(val: str) -> str:
+ if not val:
+ return '""'
+ if all(ws not in val for ws in " \r\n\t"):
+ return val
+ return repr(val)
+
+
def parsearg(manager: CommandManager, spec: str, argtype: type) -> typing.Any:
"""
Convert a string to a argument to the appropriate type.
@@ -304,14 +319,14 @@ def parsearg(manager: CommandManager, spec: str, argtype: type) -> typing.Any:
raise exceptions.CommandError from e
-def command(name: typing.Optional[str]):
+def command(name: typing.Optional[str] = None):
def decorator(function):
@functools.wraps(function)
def wrapper(*args, **kwargs):
verify_arg_signature(function, args, kwargs)
return function(*args, **kwargs)
- wrapper.__dict__["command_name"] = name or function.__name__
+ wrapper.__dict__["command_name"] = name or function.__name__.replace("_", ".")
return wrapper
return decorator
diff --git a/mitmproxy/tools/console/commander/commander.py b/mitmproxy/tools/console/commander/commander.py
index f826b984..d751422b 100644
--- a/mitmproxy/tools/console/commander/commander.py
+++ b/mitmproxy/tools/console/commander/commander.py
@@ -14,7 +14,7 @@ import mitmproxy.types
class Completer:
@abc.abstractmethod
- def cycle(self, forward: bool) -> str:
+ def cycle(self, forward: bool = True) -> str:
raise NotImplementedError()
@@ -32,7 +32,7 @@ class ListCompleter(Completer):
self.options.sort()
self.offset = 0
- def cycle(self, forward: bool) -> str:
+ def cycle(self, forward: bool = True) -> str:
if not self.options:
return self.start
ret = self.options[self.offset]
@@ -98,7 +98,7 @@ class CommandBuffer:
def right(self) -> None:
self.cursor = self.cursor + 1
- def cycle_completion(self, forward: bool) -> None:
+ def cycle_completion(self, forward: bool = True) -> None:
if not self.completion:
parts, remaining = self.master.commands.parse_partial(self.text[:self.cursor])
if parts and parts[-1].type != mitmproxy.types.Space:
@@ -211,7 +211,7 @@ class CommandEdit(urwid.WidgetWrap):
elif key == "shift tab":
self.cbuf.cycle_completion(False)
elif key == "tab":
- self.cbuf.cycle_completion(True)
+ self.cbuf.cycle_completion()
elif len(key) == 1:
self.cbuf.insert(key)
self.update()
diff --git a/mitmproxy/tools/console/commands.py b/mitmproxy/tools/console/commands.py
index d35a6b8a..26a99b14 100644
--- a/mitmproxy/tools/console/commands.py
+++ b/mitmproxy/tools/console/commands.py
@@ -25,7 +25,7 @@ class CommandItem(urwid.WidgetWrap):
if self.cmd.parameters:
parts += [
("text", " "),
- ("text", " ".join(name for name, t in self.cmd.parameters)),
+ ("text", " ".join(str(param) for param in self.cmd.parameters)),
]
if self.cmd.return_type:
parts += [
diff --git a/mitmproxy/tools/console/consoleaddons.py b/mitmproxy/tools/console/consoleaddons.py
index b5263f6f..4288696a 100644
--- a/mitmproxy/tools/console/consoleaddons.py
+++ b/mitmproxy/tools/console/consoleaddons.py
@@ -287,21 +287,22 @@ class ConsoleAddon:
)
@command.command("console.command")
- def console_command(self, *cmdstr: str) -> None:
+ def console_command(self, *cmd_str: str) -> None:
"""
Prompt the user to edit a command with a (possibly empty) starting value.
"""
- signals.status_prompt_command.send(partial=" ".join(cmdstr)) # type: ignore
+ cmd_str = (command.quote(x) if x else "" for x in cmd_str)
+ signals.status_prompt_command.send(partial=" ".join(cmd_str)) # type: ignore
@command.command("console.command.set")
def console_command_set(self, option_name: str) -> None:
"""
- Prompt the user to set an option of the form "key[=value]".
+ Prompt the user to set an option.
"""
option_value = getattr(self.master.options, option_name, None)
- current_value = option_value if option_value else ""
+ option_value = command.quote(option_value)
self.master.commands.execute(
- "console.command set %s=%s" % (option_name, current_value)
+ f"console.command set {option_name} {option_value}"
)
@command.command("console.view.keybindings")
diff --git a/test/mitmproxy/tools/console/test_commander.py b/test/mitmproxy/tools/console/test_commander.py
index ce789d30..6b42de76 100644
--- a/test/mitmproxy/tools/console/test_commander.py
+++ b/test/mitmproxy/tools/console/test_commander.py
@@ -25,7 +25,7 @@ class TestListCompleter:
for start, options, cycle in tests:
c = commander.ListCompleter(start, options)
for expected in cycle:
- assert c.cycle(True) == expected
+ assert c.cycle() == expected
class TestCommandEdit:
@@ -252,7 +252,7 @@ class TestCommandBuffer:
cb = commander.CommandBuffer(tctx.master)
cb.text = "foo bar"
cb.cursor = len(cb.text)
- cb.cycle_completion(True)
+ cb.cycle_completion()
ch = commander.CommandHistory(tctx.master, 30)
ce = commander.CommandEdit(tctx.master, "se", ch)