Add options.default_contentview

This is the first step in a longer process of revamping content views. For the
moment, the option is not exposed on the command line.
This commit is contained in:
Aldo Cortesi 2016-10-30 12:05:37 +13:00
parent 944dcbaaa0
commit b9eb1a3479
8 changed files with 35 additions and 36 deletions

View File

@ -24,6 +24,7 @@ class Dumper:
self.flow_detail = None # type: int
self.outfp = None # type: typing.io.TextIO
self.showhost = None # type: bool
self.default_contentview = "auto" # type: str
def configure(self, options, updated):
if options.filtstr:
@ -37,6 +38,7 @@ class Dumper:
self.flow_detail = options.flow_detail
self.outfp = options.tfile
self.showhost = options.showhost
self.default_contentview = options.default_contentview
def echo(self, text, ident=None, **style):
if ident:
@ -61,7 +63,7 @@ class Dumper:
self.echo(headers, ident=4)
if self.flow_detail >= 3:
_, lines, error = contentviews.get_message_content_view(
contentviews.get("Auto"),
self.default_contentview,
message
)
if error:

View File

@ -2,15 +2,16 @@
Mitmproxy Content Views
=======================
mitmproxy includes a set of content views which can be used to format/decode/highlight data.
While they are currently used for HTTP message bodies only, the may be used in other contexts
in the future, e.g. to decode protobuf messages sent as WebSocket frames.
Thus, the View API is very minimalistic. The only arguments are `data` and `**metadata`,
where `data` is the actual content (as bytes). The contents on metadata depend on the protocol in
use. For HTTP, the message headers are passed as the ``headers`` keyword argument. For HTTP
requests, the query parameters are passed as the ``query`` keyword argument.
mitmproxy includes a set of content views which can be used to
format/decode/highlight data. While they are currently used for HTTP message
bodies only, the may be used in other contexts in the future, e.g. to decode
protobuf messages sent as WebSocket frames.
Thus, the View API is very minimalistic. The only arguments are `data` and
`**metadata`, where `data` is the actual content (as bytes). The contents on
metadata depend on the protocol in use. For HTTP, the message headers are
passed as the ``headers`` keyword argument. For HTTP requests, the query
parameters are passed as the ``query`` keyword argument.
"""
import datetime
@ -97,11 +98,7 @@ class View:
prompt = ()
content_types = []
def __call__(
self,
data: bytes,
**metadata
):
def __call__(self, data: bytes, **metadata):
"""
Transform raw data into human-readable output.
@ -528,7 +525,7 @@ view_prompts = []
def get(name):
for i in views:
if i.name == name:
if i.name.lower() == name.lower():
return i
@ -606,10 +603,13 @@ def safe_to_print(lines, encoding="utf8"):
yield clean_line
def get_message_content_view(viewmode, message):
def get_message_content_view(viewname, message):
"""
Like get_content_view, but also handles message encoding.
"""
viewmode = get(viewname)
if not viewmode:
get("auto")
try:
content = message.content
except ValueError:

View File

@ -47,6 +47,7 @@ class Options(optmanager.OptManager):
stickyauth: Optional[str] = None,
stream_large_bodies: Optional[int] = None,
verbosity: int = 2,
default_contentview: str = "auto",
outfile: Optional[Tuple[str, str]] = None,
server_replay_ignore_content: bool = False,
server_replay_ignore_params: Sequence[str] = (),
@ -106,6 +107,7 @@ class Options(optmanager.OptManager):
self.stickyauth = stickyauth
self.stream_large_bodies = stream_large_bodies
self.verbosity = verbosity
self.default_contentview = default_contentview
self.outfile = outfile
self.server_replay_ignore_content = server_replay_ignore_content
self.server_replay_ignore_params = server_replay_ignore_params

View File

@ -241,7 +241,7 @@ class FlowView(tabs.Tabs):
self.flow,
(self.tab_offset, "prettyview")
)
return self.state.default_body_view if override is None else override
return self.master.options.default_contentview if override is None else override
def conn_text(self, conn):
if conn:
@ -264,7 +264,7 @@ class FlowView(tabs.Tabs):
" ",
('heading', "["),
('heading_key', "m"),
('heading', (":%s]" % viewmode.name)),
('heading', (":%s]" % viewmode)),
],
align="right"
)
@ -491,7 +491,7 @@ class FlowView(tabs.Tabs):
self.state.add_flow_setting(
self.flow,
(self.tab_offset, "prettyview"),
contentviews.get_by_shortcut(t)
contentviews.get_by_shortcut(t).name
)
signals.flow_change.send(self, flow = self.flow)

View File

@ -15,7 +15,6 @@ import urwid
from typing import Optional
from mitmproxy import addons
from mitmproxy import contentviews
from mitmproxy import controller
from mitmproxy import exceptions
from mitmproxy import master
@ -49,7 +48,6 @@ class ConsoleState(state.State):
state.State.__init__(self)
self.focus = None
self.follow_focus = None
self.default_body_view = contentviews.get("Auto")
self.flowsettings = weakref.WeakKeyDictionary()
self.last_search = None
self.last_filter = ""
@ -612,11 +610,6 @@ class ConsoleMaster(master.Master):
signals.flowlist_change.send(self)
return v
def change_default_display_mode(self, t):
v = contentviews.get_by_shortcut(t)
self.state.default_body_view = v
self.refresh_focus()
def edit_scripts(self, scripts):
self.options.scripts = [x[0] for x in scripts]

View File

@ -60,7 +60,7 @@ class Options(urwid.WidgetWrap):
select.Option(
"Default Display Mode",
"M",
self.has_default_displaymode,
lambda: self.master.options.default_contentview != "auto",
self.default_displaymode
),
select.Option(
@ -231,11 +231,13 @@ class Options(urwid.WidgetWrap):
signals.status_prompt_onekey.send(
prompt = "Global default display mode",
keys = contentviews.view_prompts,
callback = self.master.change_default_display_mode
callback = self.change_default_display_mode
)
def has_default_displaymode(self):
return self.master.state.default_body_view.name != "Auto"
def change_default_display_mode(self, t):
v = contentviews.get_by_shortcut(t)
self.master.options.default_contentview = v.name
self.master.refresh_focus()
def sticky_auth(self):
signals.status_prompt.send(

View File

@ -176,10 +176,10 @@ class StatusBar(urwid.WidgetWrap):
r.append("[")
r.append(("heading_key", "u"))
r.append(":%s]" % self.master.options.stickyauth)
if self.master.state.default_body_view.name != "Auto":
if self.master.options.default_contentview != "auto":
r.append("[")
r.append(("heading_key", "M"))
r.append(":%s]" % self.master.state.default_body_view.name)
r.append(":%s]" % self.master.options.default_contentview)
opts = []
if self.master.options.anticache:

View File

@ -233,19 +233,19 @@ def test_get_content_view():
def test_get_message_content_view():
r = mitmproxy.test.tutils.treq()
desc, lines, err = cv.get_message_content_view(cv.get("Raw"), r)
desc, lines, err = cv.get_message_content_view("raw", r)
assert desc == "Raw"
r.encode("gzip")
desc, lines, err = cv.get_message_content_view(cv.get("Raw"), r)
desc, lines, err = cv.get_message_content_view("raw", r)
assert desc == "[decoded gzip] Raw"
r.headers["content-encoding"] = "deflate"
desc, lines, err = cv.get_message_content_view(cv.get("Raw"), r)
desc, lines, err = cv.get_message_content_view("raw", r)
assert desc == "[cannot decode] Raw"
r.content = None
desc, lines, err = cv.get_message_content_view(cv.get("Raw"), r)
desc, lines, err = cv.get_message_content_view("raw", r)
assert list(lines) == [[("error", "content missing")]]