improve dumper addon text alignment (#1415)

This commit is contained in:
Maximilian Hils 2016-07-23 12:01:05 -07:00 committed by GitHub
parent c58db1adf3
commit fcb906dc97
4 changed files with 54 additions and 37 deletions

View File

@ -5,6 +5,8 @@ import traceback
import click import click
import typing # noqa
from mitmproxy import contentviews from mitmproxy import contentviews
from mitmproxy import ctx from mitmproxy import ctx
from mitmproxy import exceptions from mitmproxy import exceptions
@ -19,12 +21,25 @@ def indent(n, text):
return "\n".join(pad + i for i in l) return "\n".join(pad + i for i in l)
class Dumper(): class Dumper(object):
def __init__(self): def __init__(self):
self.filter = None self.filter = None # type: filt.TFilter
self.flow_detail = None self.flow_detail = None # type: int
self.outfp = None self.outfp = None # type: typing.io.TextIO
self.showhost = None self.showhost = None # type: bool
def configure(self, options, updated):
if options.filtstr:
self.filter = filt.parse(options.filtstr)
if not self.filter:
raise exceptions.OptionsError(
"Invalid filter expression: %s" % options.filtstr
)
else:
self.filter = None
self.flow_detail = options.flow_detail
self.outfp = options.tfile
self.showhost = options.showhost
def echo(self, text, ident=None, **style): def echo(self, text, ident=None, **style):
if ident: if ident:
@ -59,7 +74,7 @@ class Dumper():
self.echo("") self.echo("")
try: try:
type, lines = contentviews.get_content_view( _, lines = contentviews.get_content_view(
contentviews.get("Auto"), contentviews.get("Auto"),
content, content,
headers=getattr(message, "headers", None) headers=getattr(message, "headers", None)
@ -67,7 +82,7 @@ class Dumper():
except exceptions.ContentViewException: except exceptions.ContentViewException:
s = "Content viewer failed: \n" + traceback.format_exc() s = "Content viewer failed: \n" + traceback.format_exc()
ctx.log.debug(s) ctx.log.debug(s)
type, lines = contentviews.get_content_view( _, lines = contentviews.get_content_view(
contentviews.get("Raw"), contentviews.get("Raw"),
content, content,
headers=getattr(message, "headers", None) headers=getattr(message, "headers", None)
@ -114,9 +129,8 @@ class Dumper():
if flow.client_conn: if flow.client_conn:
client = click.style( client = click.style(
strutils.escape_control_characters( strutils.escape_control_characters(
flow.client_conn.address.host repr(flow.client_conn.address)
), )
bold=True
) )
elif flow.request.is_replay: elif flow.request.is_replay:
client = click.style("[replay]", fg="yellow", bold=True) client = click.style("[replay]", fg="yellow", bold=True)
@ -139,17 +153,23 @@ class Dumper():
url = flow.request.url url = flow.request.url
url = click.style(strutils.escape_control_characters(url), bold=True) url = click.style(strutils.escape_control_characters(url), bold=True)
httpversion = "" http_version = ""
if flow.request.http_version not in ("HTTP/1.1", "HTTP/1.0"): if flow.request.http_version not in ("HTTP/1.1", "HTTP/1.0"):
# We hide "normal" HTTP 1. # We hide "normal" HTTP 1.
httpversion = " " + flow.request.http_version http_version = " " + flow.request.http_version
line = "{stickycookie}{client} {method} {url}{httpversion}".format( if self.flow_detail >= 2:
stickycookie=stickycookie, linebreak = "\n "
else:
linebreak = ""
line = "{client}: {linebreak}{stickycookie}{method} {url}{http_version}".format(
client=client, client=client,
stickycookie=stickycookie,
linebreak=linebreak,
method=method, method=method,
url=url, url=url,
httpversion=httpversion http_version=http_version
) )
self.echo(line) self.echo(line)
@ -185,9 +205,14 @@ class Dumper():
size = human.pretty_size(len(flow.response.raw_content)) size = human.pretty_size(len(flow.response.raw_content))
size = click.style(size, bold=True) size = click.style(size, bold=True)
arrows = click.style(" <<", bold=True) arrows = click.style(" <<", bold=True)
if self.flow_detail == 1:
# This aligns the HTTP response code with the HTTP request method:
# 127.0.0.1:59519: GET http://example.com/
# << 304 Not Modified 0b
arrows = " " * (len(repr(flow.client_conn.address)) - 2) + arrows
line = "{replay} {arrows} {code} {reason} {size}".format( line = "{replay}{arrows} {code} {reason} {size}".format(
replay=replay, replay=replay,
arrows=arrows, arrows=arrows,
code=code, code=code,
@ -211,25 +236,12 @@ class Dumper():
def match(self, f): def match(self, f):
if self.flow_detail == 0: if self.flow_detail == 0:
return False return False
if not self.filt: if not self.filter:
return True return True
elif f.match(self.filt): elif f.match(self.filter):
return True return True
return False return False
def configure(self, options, updated):
if options.filtstr:
self.filt = filt.parse(options.filtstr)
if not self.filt:
raise exceptions.OptionsError(
"Invalid filter expression: %s" % options.filtstr
)
else:
self.filt = None
self.flow_detail = options.flow_detail
self.outfp = options.tfile
self.showhost = options.showhost
def response(self, f): def response(self, f):
if self.match(f): if self.match(f):
self.echo_flow(f) self.echo_flow(f)
@ -239,8 +251,7 @@ class Dumper():
self.echo_flow(f) self.echo_flow(f)
def tcp_message(self, f): def tcp_message(self, f):
# FIXME: Filter should be applied here if not self.match(f):
if self.options.flow_detail == 0:
return return
message = f.messages[-1] message = f.messages[-1]
direction = "->" if message.from_client else "<-" direction = "->" if message.from_client else "<-"

View File

@ -1,4 +1,4 @@
from typing import Callable # noqa from typing import Callable # noqa
master = None # type: "mitmproxy.flow.FlowMaster" master = None # type: "mitmproxy.flow.FlowMaster"
log = None # type: Callable[[str], None] log = None # type: "mitmproxy.controller.Log"

View File

@ -39,9 +39,12 @@ import functools
from mitmproxy.models.http import HTTPFlow from mitmproxy.models.http import HTTPFlow
from mitmproxy.models.tcp import TCPFlow from mitmproxy.models.tcp import TCPFlow
from mitmproxy.models.flow import Flow
from netlib import strutils from netlib import strutils
import pyparsing as pp import pyparsing as pp
from typing import Callable
def only(*types): def only(*types):
@ -471,7 +474,11 @@ def _make():
bnf = _make() bnf = _make()
TFilter = Callable[[Flow], bool]
def parse(s): def parse(s):
# type: (str) -> TFilter
try: try:
filt = bnf.parseString(s, parseAll=True)[0] filt = bnf.parseString(s, parseAll=True)[0]
filt.pattern = s filt.pattern = s

View File

@ -51,8 +51,7 @@ else:
def escape_control_characters(text, keep_spacing=True): def escape_control_characters(text, keep_spacing=True):
""" """
Replace all unicode C1 control characters from the given text with their respective control pictures. Replace all unicode C1 control characters from the given text with a single "."
For example, a null byte is replaced with the unicode character "\u2400".
Args: Args:
keep_spacing: If True, tabs and newlines will not be replaced. keep_spacing: If True, tabs and newlines will not be replaced.