Merge pull request #3371 from JessicaFavin/proper-display-on-stderr

Display errors on sys.stderr
This commit is contained in:
Maximilian Hils 2018-11-09 08:58:41 +01:00 committed by GitHub
commit 3f3ed4743a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 41 additions and 11 deletions

View File

@ -27,9 +27,10 @@ def colorful(line, styles):
class Dumper: class Dumper:
def __init__(self, outfile=sys.stdout): def __init__(self, outfile=sys.stdout, errfile=sys.stderr):
self.filter: flowfilter.TFilter = None self.filter: flowfilter.TFilter = None
self.outfp: typing.io.TextIO = outfile self.outfp: typing.io.TextIO = outfile
self.errfp: typing.io.TextIO = errfile
def load(self, loader): def load(self, loader):
loader.add_option( loader.add_option(
@ -70,6 +71,11 @@ class Dumper:
if self.outfp: if self.outfp:
self.outfp.flush() self.outfp.flush()
def echo_error(self, text, **style):
click.secho(text, file=self.errfp, **style)
if self.errfp:
self.errfp.flush()
def _echo_headers(self, headers): def _echo_headers(self, headers):
for k, v in headers.fields: for k, v in headers.fields:
k = strutils.bytes_to_escaped_str(k) k = strutils.bytes_to_escaped_str(k)
@ -243,7 +249,7 @@ class Dumper:
self.echo_flow(f) self.echo_flow(f)
def websocket_error(self, f): def websocket_error(self, f):
self.echo( self.echo_error(
"Error in WebSocket connection to {}: {}".format( "Error in WebSocket connection to {}: {}".format(
human.format_address(f.server_conn.address), f.error human.format_address(f.server_conn.address), f.error
), ),
@ -268,7 +274,7 @@ class Dumper:
f.close_reason)) f.close_reason))
def tcp_error(self, f): def tcp_error(self, f):
self.echo( self.echo_error(
"Error in TCP connection to {}: {}".format( "Error in TCP connection to {}: {}".format(
human.format_address(f.server_conn.address), f.error human.format_address(f.server_conn.address), f.error
), ),

View File

@ -32,37 +32,50 @@ def test_configure():
def test_simple(): def test_simple():
sio = io.StringIO() sio = io.StringIO()
d = dumper.Dumper(sio) sio_err = io.StringIO()
d = dumper.Dumper(sio, sio_err)
with taddons.context(d) as ctx: with taddons.context(d) as ctx:
ctx.configure(d, flow_detail=0) ctx.configure(d, flow_detail=0)
d.response(tflow.tflow(resp=True)) d.response(tflow.tflow(resp=True))
assert not sio.getvalue() assert not sio.getvalue()
sio.truncate(0) sio.truncate(0)
assert not sio_err.getvalue()
sio_err.truncate(0)
ctx.configure(d, flow_detail=1) ctx.configure(d, flow_detail=1)
d.response(tflow.tflow(resp=True)) d.response(tflow.tflow(resp=True))
assert sio.getvalue() assert sio.getvalue()
sio.truncate(0) sio.truncate(0)
assert not sio_err.getvalue()
sio_err.truncate(0)
ctx.configure(d, flow_detail=1) ctx.configure(d, flow_detail=1)
d.error(tflow.tflow(err=True)) d.error(tflow.tflow(err=True))
assert sio.getvalue() assert sio.getvalue()
sio.truncate(0) sio.truncate(0)
assert not sio_err.getvalue()
sio_err.truncate(0)
ctx.configure(d, flow_detail=4) ctx.configure(d, flow_detail=4)
d.response(tflow.tflow(resp=True)) d.response(tflow.tflow(resp=True))
assert sio.getvalue() assert sio.getvalue()
sio.truncate(0) sio.truncate(0)
assert not sio_err.getvalue()
sio_err.truncate(0)
ctx.configure(d, flow_detail=4) ctx.configure(d, flow_detail=4)
d.response(tflow.tflow(resp=True)) d.response(tflow.tflow(resp=True))
assert "<<" in sio.getvalue() assert "<<" in sio.getvalue()
sio.truncate(0) sio.truncate(0)
assert not sio_err.getvalue()
sio_err.truncate(0)
ctx.configure(d, flow_detail=4) ctx.configure(d, flow_detail=4)
d.response(tflow.tflow(err=True)) d.response(tflow.tflow(err=True))
assert "<<" in sio.getvalue() assert "<<" in sio.getvalue()
sio.truncate(0) sio.truncate(0)
assert not sio_err.getvalue()
sio_err.truncate(0)
ctx.configure(d, flow_detail=4) ctx.configure(d, flow_detail=4)
flow = tflow.tflow() flow = tflow.tflow()
@ -75,6 +88,8 @@ def test_simple():
d.response(flow) d.response(flow)
assert sio.getvalue() assert sio.getvalue()
sio.truncate(0) sio.truncate(0)
assert not sio_err.getvalue()
sio_err.truncate(0)
ctx.configure(d, flow_detail=4) ctx.configure(d, flow_detail=4)
flow = tflow.tflow(resp=tutils.tresp(content=b"{")) flow = tflow.tflow(resp=tutils.tresp(content=b"{"))
@ -83,6 +98,8 @@ def test_simple():
d.response(flow) d.response(flow)
assert sio.getvalue() assert sio.getvalue()
sio.truncate(0) sio.truncate(0)
assert not sio_err.getvalue()
sio_err.truncate(0)
ctx.configure(d, flow_detail=4) ctx.configure(d, flow_detail=4)
flow = tflow.tflow() flow = tflow.tflow()
@ -92,6 +109,8 @@ def test_simple():
d.response(flow) d.response(flow)
assert "content missing" in sio.getvalue() assert "content missing" in sio.getvalue()
sio.truncate(0) sio.truncate(0)
assert not sio_err.getvalue()
sio_err.truncate(0)
def test_echo_body(): def test_echo_body():
@ -100,7 +119,8 @@ def test_echo_body():
f.response.content = b"foo bar voing\n" * 100 f.response.content = b"foo bar voing\n" * 100
sio = io.StringIO() sio = io.StringIO()
d = dumper.Dumper(sio) sio_err = io.StringIO()
d = dumper.Dumper(sio, sio_err)
with taddons.context(d) as ctx: with taddons.context(d) as ctx:
ctx.configure(d, flow_detail=3) ctx.configure(d, flow_detail=3)
d._echo_message(f.response) d._echo_message(f.response)
@ -110,7 +130,8 @@ def test_echo_body():
def test_echo_request_line(): def test_echo_request_line():
sio = io.StringIO() sio = io.StringIO()
d = dumper.Dumper(sio) sio_err = io.StringIO()
d = dumper.Dumper(sio, sio_err)
with taddons.context(d) as ctx: with taddons.context(d) as ctx:
ctx.configure(d, flow_detail=3, showhost=True) ctx.configure(d, flow_detail=3, showhost=True)
f = tflow.tflow(client_conn=None, server_conn=True, resp=True) f = tflow.tflow(client_conn=None, server_conn=True, resp=True)
@ -146,7 +167,8 @@ class TestContentView:
with mock.patch("mitmproxy.contentviews.auto.ViewAuto.__call__") as va: with mock.patch("mitmproxy.contentviews.auto.ViewAuto.__call__") as va:
va.side_effect = exceptions.ContentViewException("") va.side_effect = exceptions.ContentViewException("")
sio = io.StringIO() sio = io.StringIO()
d = dumper.Dumper(sio) sio_err = io.StringIO()
d = dumper.Dumper(sio, sio_err)
with taddons.context(d) as ctx: with taddons.context(d) as ctx:
ctx.configure(d, flow_detail=4) ctx.configure(d, flow_detail=4)
d.response(tflow.tflow()) d.response(tflow.tflow())
@ -155,7 +177,8 @@ class TestContentView:
def test_tcp(): def test_tcp():
sio = io.StringIO() sio = io.StringIO()
d = dumper.Dumper(sio) sio_err = io.StringIO()
d = dumper.Dumper(sio, sio_err)
with taddons.context(d) as ctx: with taddons.context(d) as ctx:
ctx.configure(d, flow_detail=3, showhost=True) ctx.configure(d, flow_detail=3, showhost=True)
f = tflow.ttcpflow() f = tflow.ttcpflow()
@ -165,12 +188,13 @@ def test_tcp():
f = tflow.ttcpflow(client_conn=True, err=True) f = tflow.ttcpflow(client_conn=True, err=True)
d.tcp_error(f) d.tcp_error(f)
assert "Error in TCP" in sio.getvalue() assert "Error in TCP" in sio_err.getvalue()
def test_websocket(): def test_websocket():
sio = io.StringIO() sio = io.StringIO()
d = dumper.Dumper(sio) sio_err = io.StringIO()
d = dumper.Dumper(sio, sio_err)
with taddons.context(d) as ctx: with taddons.context(d) as ctx:
ctx.configure(d, flow_detail=3, showhost=True) ctx.configure(d, flow_detail=3, showhost=True)
f = tflow.twebsocketflow() f = tflow.twebsocketflow()
@ -183,4 +207,4 @@ def test_websocket():
f = tflow.twebsocketflow(client_conn=True, err=True) f = tflow.twebsocketflow(client_conn=True, err=True)
d.websocket_error(f) d.websocket_error(f)
assert "Error in WebSocket" in sio.getvalue() assert "Error in WebSocket" in sio_err.getvalue()