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

View File

@ -2,15 +2,16 @@
Mitmproxy Content Views Mitmproxy Content Views
======================= =======================
mitmproxy includes a set of content views which can be used to format/decode/highlight data. mitmproxy includes a set of content views which can be used to
While they are currently used for HTTP message bodies only, the may be used in other contexts format/decode/highlight data. While they are currently used for HTTP message
in the future, e.g. to decode protobuf messages sent as WebSocket frames. 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.
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 import datetime
@ -97,11 +98,7 @@ class View:
prompt = () prompt = ()
content_types = [] content_types = []
def __call__( def __call__(self, data: bytes, **metadata):
self,
data: bytes,
**metadata
):
""" """
Transform raw data into human-readable output. Transform raw data into human-readable output.
@ -528,7 +525,7 @@ view_prompts = []
def get(name): def get(name):
for i in views: for i in views:
if i.name == name: if i.name.lower() == name.lower():
return i return i
@ -606,10 +603,13 @@ def safe_to_print(lines, encoding="utf8"):
yield clean_line 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. Like get_content_view, but also handles message encoding.
""" """
viewmode = get(viewname)
if not viewmode:
get("auto")
try: try:
content = message.content content = message.content
except ValueError: except ValueError:

View File

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

View File

@ -241,7 +241,7 @@ class FlowView(tabs.Tabs):
self.flow, self.flow,
(self.tab_offset, "prettyview") (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): def conn_text(self, conn):
if conn: if conn:
@ -264,7 +264,7 @@ class FlowView(tabs.Tabs):
" ", " ",
('heading', "["), ('heading', "["),
('heading_key', "m"), ('heading_key', "m"),
('heading', (":%s]" % viewmode.name)), ('heading', (":%s]" % viewmode)),
], ],
align="right" align="right"
) )
@ -491,7 +491,7 @@ class FlowView(tabs.Tabs):
self.state.add_flow_setting( self.state.add_flow_setting(
self.flow, self.flow,
(self.tab_offset, "prettyview"), (self.tab_offset, "prettyview"),
contentviews.get_by_shortcut(t) contentviews.get_by_shortcut(t).name
) )
signals.flow_change.send(self, flow = self.flow) signals.flow_change.send(self, flow = self.flow)

View File

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

View File

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

View File

@ -176,10 +176,10 @@ class StatusBar(urwid.WidgetWrap):
r.append("[") r.append("[")
r.append(("heading_key", "u")) r.append(("heading_key", "u"))
r.append(":%s]" % self.master.options.stickyauth) 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("[")
r.append(("heading_key", "M")) r.append(("heading_key", "M"))
r.append(":%s]" % self.master.state.default_body_view.name) r.append(":%s]" % self.master.options.default_contentview)
opts = [] opts = []
if self.master.options.anticache: if self.master.options.anticache:

View File

@ -233,19 +233,19 @@ def test_get_content_view():
def test_get_message_content_view(): def test_get_message_content_view():
r = mitmproxy.test.tutils.treq() 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" assert desc == "Raw"
r.encode("gzip") 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" assert desc == "[decoded gzip] Raw"
r.headers["content-encoding"] = "deflate" 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" assert desc == "[cannot decode] Raw"
r.content = None 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")]] assert list(lines) == [[("error", "content missing")]]