mirror of
https://github.com/Grasscutters/mitmproxy.git
synced 2024-11-23 08:11:00 +00:00
improve dumper addon text alignment (#1415)
This commit is contained in:
parent
c58db1adf3
commit
fcb906dc97
@ -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 "<-"
|
||||||
|
@ -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"
|
||||||
|
@ -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
|
||||||
|
@ -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.
|
||||||
|
Loading…
Reference in New Issue
Block a user