aboutsummaryrefslogtreecommitdiffstats
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/mitmproxy/builtins/test_clientplayback.py37
-rw-r--r--test/mitmproxy/builtins/test_script.py25
-rw-r--r--test/mitmproxy/builtins/test_serverplayback.py284
-rw-r--r--test/mitmproxy/console/test_master.py2
-rw-r--r--test/mitmproxy/mastertest.py21
-rw-r--r--test/mitmproxy/protocol/test_http1.py12
-rw-r--r--test/mitmproxy/protocol/test_http2.py49
-rw-r--r--test/mitmproxy/test_addons.py4
-rw-r--r--test/mitmproxy/test_dump.py11
-rw-r--r--test/mitmproxy/test_flow.py358
-rw-r--r--test/mitmproxy/test_fuzzing.py9
-rw-r--r--test/mitmproxy/test_server.py337
-rw-r--r--test/mitmproxy/tservers.py49
-rw-r--r--test/netlib/http/test_headers.py9
-rw-r--r--test/netlib/http/test_response.py5
-rw-r--r--test/netlib/test_encoding.py59
-rw-r--r--test/netlib/test_strutils.py2
-rw-r--r--test/pathod/test_protocols_http2.py6
18 files changed, 678 insertions, 601 deletions
diff --git a/test/mitmproxy/builtins/test_clientplayback.py b/test/mitmproxy/builtins/test_clientplayback.py
new file mode 100644
index 00000000..15702340
--- /dev/null
+++ b/test/mitmproxy/builtins/test_clientplayback.py
@@ -0,0 +1,37 @@
+import mock
+
+from mitmproxy.builtins import clientplayback
+from mitmproxy import options
+
+from .. import tutils, mastertest
+
+
+class TestClientPlayback:
+ def test_playback(self):
+ cp = clientplayback.ClientPlayback()
+ cp.configure(options.Options(), [])
+ assert cp.count() == 0
+ f = tutils.tflow(resp=True)
+ cp.load([f])
+ assert cp.count() == 1
+ RP = "mitmproxy.protocol.http_replay.RequestReplayThread"
+ with mock.patch(RP) as rp:
+ assert not cp.current
+ with mastertest.mockctx():
+ cp.tick()
+ rp.assert_called()
+ assert cp.current
+
+ cp.keepserving = False
+ cp.flows = None
+ cp.current = None
+ with mock.patch("mitmproxy.controller.Master.shutdown") as sd:
+ with mastertest.mockctx():
+ cp.tick()
+ sd.assert_called()
+
+ def test_configure(self):
+ cp = clientplayback.ClientPlayback()
+ cp.configure(
+ options.Options(), []
+ )
diff --git a/test/mitmproxy/builtins/test_script.py b/test/mitmproxy/builtins/test_script.py
index 0bac6ca0..09e5bc92 100644
--- a/test/mitmproxy/builtins/test_script.py
+++ b/test/mitmproxy/builtins/test_script.py
@@ -137,6 +137,31 @@ class TestScript(mastertest.MasterTest):
class TestScriptLoader(mastertest.MasterTest):
+ def test_run_once(self):
+ s = state.State()
+ o = options.Options(scripts=[])
+ m = master.FlowMaster(o, None, s)
+ sl = script.ScriptLoader()
+ m.addons.add(o, sl)
+
+ f = tutils.tflow(resp=True)
+ with m.handlecontext():
+ sc = sl.run_once(
+ tutils.test_data.path(
+ "data/addonscripts/recorder.py"
+ ), [f]
+ )
+ evts = [i[1] for i in sc.ns.call_log]
+ assert evts == ['start', 'request', 'responseheaders', 'response', 'done']
+
+ with m.handlecontext():
+ tutils.raises(
+ "file not found",
+ sl.run_once,
+ "nonexistent",
+ [f]
+ )
+
def test_simple(self):
s = state.State()
o = options.Options(scripts=[])
diff --git a/test/mitmproxy/builtins/test_serverplayback.py b/test/mitmproxy/builtins/test_serverplayback.py
new file mode 100644
index 00000000..4db509da
--- /dev/null
+++ b/test/mitmproxy/builtins/test_serverplayback.py
@@ -0,0 +1,284 @@
+from .. import tutils, mastertest
+
+import netlib.tutils
+from mitmproxy.builtins import serverplayback
+from mitmproxy import options
+from mitmproxy import exceptions
+from mitmproxy import flow
+
+
+class TestServerPlayback:
+ def test_server_playback(self):
+ sp = serverplayback.ServerPlayback()
+ sp.configure(options.Options(), [])
+ f = tutils.tflow(resp=True)
+
+ assert not sp.flowmap
+
+ sp.load([f])
+ assert sp.flowmap
+ assert sp.next_flow(f)
+ assert not sp.flowmap
+
+ def test_ignore_host(self):
+ sp = serverplayback.ServerPlayback()
+ sp.configure(options.Options(server_replay_ignore_host=True), [])
+
+ r = tutils.tflow(resp=True)
+ r2 = tutils.tflow(resp=True)
+
+ r.request.host = "address"
+ r2.request.host = "address"
+ assert sp._hash(r) == sp._hash(r2)
+ r2.request.host = "wrong_address"
+ assert sp._hash(r) == sp._hash(r2)
+
+ def test_ignore_content(self):
+ s = serverplayback.ServerPlayback()
+ s.configure(options.Options(server_replay_ignore_content=False), [])
+
+ r = tutils.tflow(resp=True)
+ r2 = tutils.tflow(resp=True)
+
+ r.request.content = b"foo"
+ r2.request.content = b"foo"
+ assert s._hash(r) == s._hash(r2)
+ r2.request.content = b"bar"
+ assert not s._hash(r) == s._hash(r2)
+
+ s.configure(options.Options(server_replay_ignore_content=True), [])
+ r = tutils.tflow(resp=True)
+ r2 = tutils.tflow(resp=True)
+ r.request.content = b"foo"
+ r2.request.content = b"foo"
+ assert s._hash(r) == s._hash(r2)
+ r2.request.content = b"bar"
+ assert s._hash(r) == s._hash(r2)
+ r2.request.content = b""
+ assert s._hash(r) == s._hash(r2)
+ r2.request.content = None
+ assert s._hash(r) == s._hash(r2)
+
+ def test_ignore_content_wins_over_params(self):
+ s = serverplayback.ServerPlayback()
+ s.configure(
+ options.Options(
+ server_replay_ignore_content=True,
+ server_replay_ignore_payload_params=[
+ "param1", "param2"
+ ]
+ ),
+ []
+ )
+ # NOTE: parameters are mutually exclusive in options
+
+ r = tutils.tflow(resp=True)
+ r.request.headers["Content-Type"] = "application/x-www-form-urlencoded"
+ r.request.content = b"paramx=y"
+
+ r2 = tutils.tflow(resp=True)
+ r2.request.headers["Content-Type"] = "application/x-www-form-urlencoded"
+ r2.request.content = b"paramx=x"
+
+ # same parameters
+ assert s._hash(r) == s._hash(r2)
+
+ def test_ignore_payload_params_other_content_type(self):
+ s = serverplayback.ServerPlayback()
+ s.configure(
+ options.Options(
+ server_replay_ignore_content=False,
+ server_replay_ignore_payload_params=[
+ "param1", "param2"
+ ]
+ ),
+ []
+
+ )
+ r = tutils.tflow(resp=True)
+ r.request.headers["Content-Type"] = "application/json"
+ r.request.content = b'{"param1":"1"}'
+ r2 = tutils.tflow(resp=True)
+ r2.request.headers["Content-Type"] = "application/json"
+ r2.request.content = b'{"param1":"1"}'
+ # same content
+ assert s._hash(r) == s._hash(r2)
+ # distint content (note only x-www-form-urlencoded payload is analysed)
+ r2.request.content = b'{"param1":"2"}'
+ assert not s._hash(r) == s._hash(r2)
+
+ def test_hash(self):
+ s = serverplayback.ServerPlayback()
+ s.configure(options.Options(), [])
+
+ r = tutils.tflow()
+ r2 = tutils.tflow()
+
+ assert s._hash(r)
+ assert s._hash(r) == s._hash(r2)
+ r.request.headers["foo"] = "bar"
+ assert s._hash(r) == s._hash(r2)
+ r.request.path = "voing"
+ assert s._hash(r) != s._hash(r2)
+
+ r.request.path = "path?blank_value"
+ r2.request.path = "path?"
+ assert s._hash(r) != s._hash(r2)
+
+ def test_headers(self):
+ s = serverplayback.ServerPlayback()
+ s.configure(options.Options(server_replay_use_headers=["foo"]), [])
+
+ r = tutils.tflow(resp=True)
+ r.request.headers["foo"] = "bar"
+ r2 = tutils.tflow(resp=True)
+ assert not s._hash(r) == s._hash(r2)
+ r2.request.headers["foo"] = "bar"
+ assert s._hash(r) == s._hash(r2)
+ r2.request.headers["oink"] = "bar"
+ assert s._hash(r) == s._hash(r2)
+
+ r = tutils.tflow(resp=True)
+ r2 = tutils.tflow(resp=True)
+ assert s._hash(r) == s._hash(r2)
+
+ def test_load(self):
+ s = serverplayback.ServerPlayback()
+ s.configure(options.Options(), [])
+
+ r = tutils.tflow(resp=True)
+ r.request.headers["key"] = "one"
+
+ r2 = tutils.tflow(resp=True)
+ r2.request.headers["key"] = "two"
+
+ s.load([r, r2])
+
+ assert s.count() == 2
+
+ n = s.next_flow(r)
+ assert n.request.headers["key"] == "one"
+ assert s.count() == 1
+
+ n = s.next_flow(r)
+ assert n.request.headers["key"] == "two"
+ assert not s.flowmap
+ assert s.count() == 0
+
+ assert not s.next_flow(r)
+
+ def test_load_with_server_replay_nopop(self):
+ s = serverplayback.ServerPlayback()
+ s.configure(options.Options(server_replay_nopop=True), [])
+
+ r = tutils.tflow(resp=True)
+ r.request.headers["key"] = "one"
+
+ r2 = tutils.tflow(resp=True)
+ r2.request.headers["key"] = "two"
+
+ s.load([r, r2])
+
+ assert s.count() == 2
+ s.next_flow(r)
+ assert s.count() == 2
+
+ def test_ignore_params(self):
+ s = serverplayback.ServerPlayback()
+ s.configure(
+ options.Options(
+ server_replay_ignore_params=["param1", "param2"]
+ ),
+ []
+ )
+
+ r = tutils.tflow(resp=True)
+ r.request.path = "/test?param1=1"
+ r2 = tutils.tflow(resp=True)
+ r2.request.path = "/test"
+ assert s._hash(r) == s._hash(r2)
+ r2.request.path = "/test?param1=2"
+ assert s._hash(r) == s._hash(r2)
+ r2.request.path = "/test?param2=1"
+ assert s._hash(r) == s._hash(r2)
+ r2.request.path = "/test?param3=2"
+ assert not s._hash(r) == s._hash(r2)
+
+ def test_ignore_payload_params(self):
+ s = serverplayback.ServerPlayback()
+ s.configure(
+ options.Options(
+ server_replay_ignore_payload_params=["param1", "param2"]
+ ),
+ []
+ )
+
+ r = tutils.tflow(resp=True)
+ r.request.headers["Content-Type"] = "application/x-www-form-urlencoded"
+ r.request.content = b"paramx=x&param1=1"
+ r2 = tutils.tflow(resp=True)
+ r2.request.headers["Content-Type"] = "application/x-www-form-urlencoded"
+ r2.request.content = b"paramx=x&param1=1"
+ # same parameters
+ assert s._hash(r) == s._hash(r2)
+ # ignored parameters !=
+ r2.request.content = b"paramx=x&param1=2"
+ assert s._hash(r) == s._hash(r2)
+ # missing parameter
+ r2.request.content = b"paramx=x"
+ assert s._hash(r) == s._hash(r2)
+ # ignorable parameter added
+ r2.request.content = b"paramx=x&param1=2"
+ assert s._hash(r) == s._hash(r2)
+ # not ignorable parameter changed
+ r2.request.content = b"paramx=y&param1=1"
+ assert not s._hash(r) == s._hash(r2)
+ # not ignorable parameter missing
+ r2.request.content = b"param1=1"
+ assert not s._hash(r) == s._hash(r2)
+
+ def test_server_playback_full(self):
+ state = flow.State()
+ s = serverplayback.ServerPlayback()
+ o = options.Options(refresh_server_playback = True, keepserving=False)
+ m = mastertest.RecordingMaster(o, None, state)
+ m.addons.add(o, s)
+
+ f = tutils.tflow()
+ f.response = netlib.tutils.tresp(content=f.request.content)
+ s.load([f, f])
+
+ tf = tutils.tflow()
+ assert not tf.response
+ m.request(tf)
+ assert tf.response == f.response
+
+ tf = tutils.tflow()
+ tf.request.content = b"gibble"
+ assert not tf.response
+ m.request(tf)
+ assert not tf.response
+
+ assert not s.stop
+ s.tick()
+ assert not s.stop
+
+ tf = tutils.tflow()
+ m.request(tutils.tflow())
+ assert s.stop
+
+ def test_server_playback_kill(self):
+ state = flow.State()
+ s = serverplayback.ServerPlayback()
+ o = options.Options(refresh_server_playback = True, replay_kill_extra=True)
+ m = mastertest.RecordingMaster(o, None, state)
+ m.addons.add(o, s)
+
+ f = tutils.tflow()
+ f.response = netlib.tutils.tresp(content=f.request.content)
+ s.load([f])
+
+ f = tutils.tflow()
+ f.request.host = "nonexistent"
+ m.request(f)
+ assert f.reply.value == exceptions.Kill
diff --git a/test/mitmproxy/console/test_master.py b/test/mitmproxy/console/test_master.py
index fcb87e1b..8388a6bd 100644
--- a/test/mitmproxy/console/test_master.py
+++ b/test/mitmproxy/console/test_master.py
@@ -107,7 +107,7 @@ def test_format_keyvals():
def test_options():
- assert console.master.Options(kill=True)
+ assert console.master.Options(replay_kill_extra=True)
class TestMaster(mastertest.MasterTest):
diff --git a/test/mitmproxy/mastertest.py b/test/mitmproxy/mastertest.py
index 08659d19..a14fe02a 100644
--- a/test/mitmproxy/mastertest.py
+++ b/test/mitmproxy/mastertest.py
@@ -1,8 +1,14 @@
+import contextlib
+
from . import tutils
import netlib.tutils
from mitmproxy.flow import master
-from mitmproxy import flow, proxy, models, controller
+from mitmproxy import flow, proxy, models, controller, options
+
+
+class TestMaster:
+ pass
class MasterTest:
@@ -16,7 +22,9 @@ class MasterTest:
master.serverconnect(f.server_conn)
master.request(f)
if not f.error:
- f.response = models.HTTPResponse.wrap(netlib.tutils.tresp(content=content))
+ f.response = models.HTTPResponse.wrap(
+ netlib.tutils.tresp(content=content)
+ )
master.response(f)
master.clientdisconnect(f)
return f
@@ -41,3 +49,12 @@ class RecordingMaster(master.FlowMaster):
def add_log(self, e, level):
self.event_log.append((level, e))
+
+
+@contextlib.contextmanager
+def mockctx():
+ state = flow.State()
+ o = options.Options(refresh_server_playback = True, keepserving=False)
+ m = RecordingMaster(o, proxy.DummyServer(o), state)
+ with m.handlecontext():
+ yield
diff --git a/test/mitmproxy/protocol/test_http1.py b/test/mitmproxy/protocol/test_http1.py
index 7d04c56b..2fc4ac63 100644
--- a/test/mitmproxy/protocol/test_http1.py
+++ b/test/mitmproxy/protocol/test_http1.py
@@ -18,14 +18,15 @@ class TestInvalidRequests(tservers.HTTPProxyTest):
def test_double_connect(self):
p = self.pathoc()
- r = p.request("connect:'%s:%s'" % ("127.0.0.1", self.server2.port))
+ with p.connect():
+ r = p.request("connect:'%s:%s'" % ("127.0.0.1", self.server2.port))
assert r.status_code == 400
assert b"Invalid HTTP request form" in r.content
def test_relative_request(self):
p = self.pathoc_raw()
- p.connect()
- r = p.request("get:/p/200")
+ with p.connect():
+ r = p.request("get:/p/200")
assert r.status_code == 400
assert b"Invalid HTTP request form" in r.content
@@ -61,5 +62,8 @@ class TestHeadContentLength(tservers.HTTPProxyTest):
def test_head_content_length(self):
p = self.pathoc()
- resp = p.request("""head:'%s/p/200:h"Content-Length"="42"'""" % self.server.urlbase)
+ with p.connect():
+ resp = p.request(
+ """head:'%s/p/200:h"Content-Length"="42"'""" % self.server.urlbase
+ )
assert resp.headers["Content-Length"] == "42"
diff --git a/test/mitmproxy/protocol/test_http2.py b/test/mitmproxy/protocol/test_http2.py
index 1eabebf1..c4bd2049 100644
--- a/test/mitmproxy/protocol/test_http2.py
+++ b/test/mitmproxy/protocol/test_http2.py
@@ -15,7 +15,7 @@ from mitmproxy.proxy.config import ProxyConfig
import netlib
from ...netlib import tservers as netlib_tservers
from netlib.exceptions import HttpException
-from netlib.http.http2 import framereader
+from netlib.http import http1, http2
from .. import tservers
@@ -33,6 +33,11 @@ requires_alpn = pytest.mark.skipif(
reason='requires OpenSSL with ALPN support')
+# inspect the log:
+# for msg in self.proxy.tmaster.tlog:
+# print(msg)
+
+
class _Http2ServerBase(netlib_tservers.ServerTestBase):
ssl = dict(alpn_select=b'h2')
@@ -55,7 +60,7 @@ class _Http2ServerBase(netlib_tservers.ServerTestBase):
done = False
while not done:
try:
- raw = b''.join(framereader.http2_read_raw_frame(self.rfile))
+ raw = b''.join(http2.read_raw_frame(self.rfile))
events = h2_conn.receive_data(raw)
except HttpException:
print(traceback.format_exc())
@@ -124,11 +129,17 @@ class _Http2TestBase(object):
client.connect()
# send CONNECT request
- client.wfile.write(
- b"CONNECT localhost:%d HTTP/1.1\r\n"
- b"Host: localhost:%d\r\n"
- b"\r\n" % (self.server.server.address.port, self.server.server.address.port)
- )
+ client.wfile.write(http1.assemble_request(netlib.http.Request(
+ 'authority',
+ b'CONNECT',
+ b'',
+ b'localhost',
+ self.server.server.address.port,
+ b'/',
+ b'HTTP/1.1',
+ [(b'host', b'localhost:%d' % self.server.server.address.port)],
+ b'',
+ )))
client.wfile.flush()
# read CONNECT response
@@ -242,7 +253,7 @@ class TestSimple(_Http2Test):
done = False
while not done:
try:
- raw = b''.join(framereader.http2_read_raw_frame(client.rfile))
+ raw = b''.join(http2.read_raw_frame(client.rfile))
events = h2_conn.receive_data(raw)
except HttpException:
print(traceback.format_exc())
@@ -319,7 +330,7 @@ class TestRequestWithPriority(_Http2Test):
done = False
while not done:
try:
- raw = b''.join(framereader.http2_read_raw_frame(client.rfile))
+ raw = b''.join(http2.read_raw_frame(client.rfile))
events = h2_conn.receive_data(raw)
except HttpException:
print(traceback.format_exc())
@@ -358,7 +369,7 @@ class TestRequestWithPriority(_Http2Test):
done = False
while not done:
try:
- raw = b''.join(framereader.http2_read_raw_frame(client.rfile))
+ raw = b''.join(http2.read_raw_frame(client.rfile))
events = h2_conn.receive_data(raw)
except HttpException:
print(traceback.format_exc())
@@ -430,7 +441,7 @@ class TestPriority(_Http2Test):
done = False
while not done:
try:
- raw = b''.join(framereader.http2_read_raw_frame(client.rfile))
+ raw = b''.join(http2.read_raw_frame(client.rfile))
events = h2_conn.receive_data(raw)
except HttpException:
print(traceback.format_exc())
@@ -507,7 +518,7 @@ class TestPriorityWithExistingStream(_Http2Test):
done = False
while not done:
try:
- raw = b''.join(framereader.http2_read_raw_frame(client.rfile))
+ raw = b''.join(http2.read_raw_frame(client.rfile))
events = h2_conn.receive_data(raw)
except HttpException:
print(traceback.format_exc())
@@ -558,7 +569,7 @@ class TestStreamResetFromServer(_Http2Test):
done = False
while not done:
try:
- raw = b''.join(framereader.http2_read_raw_frame(client.rfile))
+ raw = b''.join(http2.read_raw_frame(client.rfile))
events = h2_conn.receive_data(raw)
except HttpException:
print(traceback.format_exc())
@@ -608,7 +619,7 @@ class TestBodySizeLimit(_Http2Test):
done = False
while not done:
try:
- raw = b''.join(framereader.http2_read_raw_frame(client.rfile))
+ raw = b''.join(http2.read_raw_frame(client.rfile))
events = h2_conn.receive_data(raw)
except HttpException:
print(traceback.format_exc())
@@ -693,7 +704,7 @@ class TestPushPromise(_Http2Test):
responses = 0
while not done:
try:
- raw = b''.join(framereader.http2_read_raw_frame(client.rfile))
+ raw = b''.join(http2.read_raw_frame(client.rfile))
events = h2_conn.receive_data(raw)
except HttpException:
print(traceback.format_exc())
@@ -746,7 +757,7 @@ class TestPushPromise(_Http2Test):
responses = 0
while not done:
try:
- raw = b''.join(framereader.http2_read_raw_frame(client.rfile))
+ raw = b''.join(http2.read_raw_frame(client.rfile))
events = h2_conn.receive_data(raw)
except HttpException:
print(traceback.format_exc())
@@ -806,7 +817,7 @@ class TestConnectionLost(_Http2Test):
done = False
while not done:
try:
- raw = b''.join(framereader.http2_read_raw_frame(client.rfile))
+ raw = b''.join(http2.read_raw_frame(client.rfile))
h2_conn.receive_data(raw)
except HttpException:
print(traceback.format_exc())
@@ -863,7 +874,7 @@ class TestMaxConcurrentStreams(_Http2Test):
ended_streams = 0
while ended_streams != len(new_streams):
try:
- header, body = framereader.http2_read_raw_frame(client.rfile)
+ header, body = http2.read_raw_frame(client.rfile)
events = h2_conn.receive_data(b''.join([header, body]))
except:
break
@@ -909,7 +920,7 @@ class TestConnectionTerminated(_Http2Test):
connection_terminated_event = None
while not done:
try:
- raw = b''.join(framereader.http2_read_raw_frame(client.rfile))
+ raw = b''.join(http2.read_raw_frame(client.rfile))
events = h2_conn.receive_data(raw)
for event in events:
if isinstance(event, h2.events.ConnectionTerminated):
diff --git a/test/mitmproxy/test_addons.py b/test/mitmproxy/test_addons.py
index a5085ea0..52d7f07f 100644
--- a/test/mitmproxy/test_addons.py
+++ b/test/mitmproxy/test_addons.py
@@ -17,5 +17,5 @@ def test_simple():
m = controller.Master(o)
a = addons.Addons(m)
a.add(o, TAddon("one"))
- assert a.has_addon("one")
- assert not a.has_addon("two")
+ assert a.get("one")
+ assert not a.get("two")
diff --git a/test/mitmproxy/test_dump.py b/test/mitmproxy/test_dump.py
index 90f33264..06f39e9d 100644
--- a/test/mitmproxy/test_dump.py
+++ b/test/mitmproxy/test_dump.py
@@ -45,18 +45,17 @@ class TestDumpMaster(mastertest.MasterTest):
m = dump.DumpMaster(None, o)
f = tutils.tflow(err=True)
m.error(f)
- assert m.error(f)
assert "error" in o.tfile.getvalue()
def test_replay(self):
- o = dump.Options(server_replay=["nonexistent"], kill=True)
- tutils.raises(dump.DumpError, dump.DumpMaster, None, o)
+ o = dump.Options(server_replay=["nonexistent"], replay_kill_extra=True)
+ tutils.raises(exceptions.OptionsError, dump.DumpMaster, None, o)
with tutils.tmpdir() as t:
p = os.path.join(t, "rep")
self.flowfile(p)
- o = dump.Options(server_replay=[p], kill=True)
+ o = dump.Options(server_replay=[p], replay_kill_extra=True)
o.verbosity = 0
o.flow_detail = 0
m = dump.DumpMaster(None, o)
@@ -64,13 +63,13 @@ class TestDumpMaster(mastertest.MasterTest):
self.cycle(m, b"content")
self.cycle(m, b"content")
- o = dump.Options(server_replay=[p], kill=False)
+ o = dump.Options(server_replay=[p], replay_kill_extra=False)
o.verbosity = 0
o.flow_detail = 0
m = dump.DumpMaster(None, o)
self.cycle(m, b"nonexistent")
- o = dump.Options(client_replay=[p], kill=False)
+ o = dump.Options(client_replay=[p], replay_kill_extra=False)
o.verbosity = 0
o.flow_detail = 0
m = dump.DumpMaster(None, o)
diff --git a/test/mitmproxy/test_flow.py b/test/mitmproxy/test_flow.py
index 1caeb100..0fe45afb 100644
--- a/test/mitmproxy/test_flow.py
+++ b/test/mitmproxy/test_flow.py
@@ -37,261 +37,6 @@ def test_app_registry():
assert ar.get(r)
-class TestClientPlaybackState:
-
- def test_tick(self):
- first = tutils.tflow()
- s = flow.State()
- fm = flow.FlowMaster(None, None, s)
- fm.start_client_playback([first, tutils.tflow()], True)
- c = fm.client_playback
- c.testing = True
-
- assert not c.done()
- assert not s.flow_count()
- assert c.count() == 2
- c.tick(fm)
- assert s.flow_count()
- assert c.count() == 1
-
- c.tick(fm)
- assert c.count() == 1
-
- c.clear(c.current)
- c.tick(fm)
- assert c.count() == 0
- c.clear(c.current)
- assert c.done()
-
- fm.state.clear()
- fm.tick(timeout=0)
-
- fm.stop_client_playback()
- assert not fm.client_playback
-
-
-class TestServerPlaybackState:
-
- def test_hash(self):
- s = flow.ServerPlaybackState(
- None,
- [],
- False,
- False,
- None,
- False,
- None,
- False)
- r = tutils.tflow()
- r2 = tutils.tflow()
-
- assert s._hash(r)
- assert s._hash(r) == s._hash(r2)
- r.request.headers["foo"] = "bar"
- assert s._hash(r) == s._hash(r2)
- r.request.path = "voing"
- assert s._hash(r) != s._hash(r2)
-
- r.request.path = "path?blank_value"
- r2.request.path = "path?"
- assert s._hash(r) != s._hash(r2)
-
- def test_headers(self):
- s = flow.ServerPlaybackState(
- ["foo"],
- [],
- False,
- False,
- None,
- False,
- None,
- False)
- r = tutils.tflow(resp=True)
- r.request.headers["foo"] = "bar"
- r2 = tutils.tflow(resp=True)
- assert not s._hash(r) == s._hash(r2)
- r2.request.headers["foo"] = "bar"
- assert s._hash(r) == s._hash(r2)
- r2.request.headers["oink"] = "bar"
- assert s._hash(r) == s._hash(r2)
-
- r = tutils.tflow(resp=True)
- r2 = tutils.tflow(resp=True)
- assert s._hash(r) == s._hash(r2)
-
- def test_load(self):
- r = tutils.tflow(resp=True)
- r.request.headers["key"] = "one"
-
- r2 = tutils.tflow(resp=True)
- r2.request.headers["key"] = "two"
-
- s = flow.ServerPlaybackState(
- None, [
- r, r2], False, False, None, False, None, False)
- assert s.count() == 2
- assert len(s.fmap.keys()) == 1
-
- n = s.next_flow(r)
- assert n.request.headers["key"] == "one"
- assert s.count() == 1
-
- n = s.next_flow(r)
- assert n.request.headers["key"] == "two"
- assert s.count() == 0
-
- assert not s.next_flow(r)
-
- def test_load_with_nopop(self):
- r = tutils.tflow(resp=True)
- r.request.headers["key"] = "one"
-
- r2 = tutils.tflow(resp=True)
- r2.request.headers["key"] = "two"
-
- s = flow.ServerPlaybackState(
- None, [
- r, r2], False, True, None, False, None, False)
-
- assert s.count() == 2
- s.next_flow(r)
- assert s.count() == 2
-
- def test_ignore_params(self):
- s = flow.ServerPlaybackState(
- None, [], False, False, [
- "param1", "param2"], False, None, False)
- r = tutils.tflow(resp=True)
- r.request.path = "/test?param1=1"
- r2 = tutils.tflow(resp=True)
- r2.request.path = "/test"
- assert s._hash(r) == s._hash(r2)
- r2.request.path = "/test?param1=2"
- assert s._hash(r) == s._hash(r2)
- r2.request.path = "/test?param2=1"
- assert s._hash(r) == s._hash(r2)
- r2.request.path = "/test?param3=2"
- assert not s._hash(r) == s._hash(r2)
-
- def test_ignore_payload_params(self):
- s = flow.ServerPlaybackState(
- None, [], False, False, None, False, [
- "param1", "param2"], False)
- r = tutils.tflow(resp=True)
- r.request.headers["Content-Type"] = "application/x-www-form-urlencoded"
- r.request.content = b"paramx=x&param1=1"
- r2 = tutils.tflow(resp=True)
- r2.request.headers["Content-Type"] = "application/x-www-form-urlencoded"
- r2.request.content = b"paramx=x&param1=1"
- # same parameters
- assert s._hash(r) == s._hash(r2)
- # ignored parameters !=
- r2.request.content = b"paramx=x&param1=2"
- assert s._hash(r) == s._hash(r2)
- # missing parameter
- r2.request.content = b"paramx=x"
- assert s._hash(r) == s._hash(r2)
- # ignorable parameter added
- r2.request.content = b"paramx=x&param1=2"
- assert s._hash(r) == s._hash(r2)
- # not ignorable parameter changed
- r2.request.content = b"paramx=y&param1=1"
- assert not s._hash(r) == s._hash(r2)
- # not ignorable parameter missing
- r2.request.content = b"param1=1"
- assert not s._hash(r) == s._hash(r2)
-
- def test_ignore_payload_params_other_content_type(self):
- s = flow.ServerPlaybackState(
- None, [], False, False, None, False, [
- "param1", "param2"], False)
- r = tutils.tflow(resp=True)
- r.request.headers["Content-Type"] = "application/json"
- r.request.content = b'{"param1":"1"}'
- r2 = tutils.tflow(resp=True)
- r2.request.headers["Content-Type"] = "application/json"
- r2.request.content = b'{"param1":"1"}'
- # same content
- assert s._hash(r) == s._hash(r2)
- # distint content (note only x-www-form-urlencoded payload is analysed)
- r2.request.content = b'{"param1":"2"}'
- assert not s._hash(r) == s._hash(r2)
-
- def test_ignore_payload_wins_over_params(self):
- # NOTE: parameters are mutually exclusive in options
- s = flow.ServerPlaybackState(
- None, [], False, False, None, True, [
- "param1", "param2"], False)
- r = tutils.tflow(resp=True)
- r.request.headers["Content-Type"] = "application/x-www-form-urlencoded"
- r.request.content = b"paramx=y"
- r2 = tutils.tflow(resp=True)
- r2.request.headers["Content-Type"] = "application/x-www-form-urlencoded"
- r2.request.content = b"paramx=x"
- # same parameters
- assert s._hash(r) == s._hash(r2)
-
- def test_ignore_content(self):
- s = flow.ServerPlaybackState(
- None,
- [],
- False,
- False,
- None,
- False,
- None,
- False)
- r = tutils.tflow(resp=True)
- r2 = tutils.tflow(resp=True)
-
- r.request.content = b"foo"
- r2.request.content = b"foo"
- assert s._hash(r) == s._hash(r2)
- r2.request.content = b"bar"
- assert not s._hash(r) == s._hash(r2)
-
- # now ignoring content
- s = flow.ServerPlaybackState(
- None,
- [],
- False,
- False,
- None,
- True,
- None,
- False)
- r = tutils.tflow(resp=True)
- r2 = tutils.tflow(resp=True)
- r.request.content = b"foo"
- r2.request.content = b"foo"
- assert s._hash(r) == s._hash(r2)
- r2.request.content = b"bar"
- assert s._hash(r) == s._hash(r2)
- r2.request.content = b""
- assert s._hash(r) == s._hash(r2)
- r2.request.content = None
- assert s._hash(r) == s._hash(r2)
-
- def test_ignore_host(self):
- s = flow.ServerPlaybackState(
- None,
- [],
- False,
- False,
- None,
- False,
- None,
- True)
- r = tutils.tflow(resp=True)
- r2 = tutils.tflow(resp=True)
-
- r.request.host = "address"
- r2.request.host = "address"
- assert s._hash(r) == s._hash(r2)
- r2.request.host = "wrong_address"
- assert s._hash(r) == s._hash(r2)
-
-
class TestHTTPFlow(object):
def test_copy(self):
@@ -699,13 +444,13 @@ class TestFlowMaster:
fm = flow.FlowMaster(None, None, s)
f = tutils.tflow(resp=True)
f.request.content = None
- assert "missing" in fm.replay_request(f)
+ tutils.raises("missing", fm.replay_request, f)
f.intercepted = True
- assert "intercepting" in fm.replay_request(f)
+ tutils.raises("intercepted", fm.replay_request, f)
f.live = True
- assert "live" in fm.replay_request(f)
+ tutils.raises("live", fm.replay_request, f)
def test_duplicate_flow(self):
s = flow.State()
@@ -743,103 +488,6 @@ class TestFlowMaster:
fm.shutdown()
- def test_client_playback(self):
- s = flow.State()
-
- f = tutils.tflow(resp=True)
- pb = [tutils.tflow(resp=True), f]
- fm = flow.FlowMaster(
- options.Options(),
- DummyServer(ProxyConfig(options.Options())),
- s
- )
- assert not fm.start_server_playback(
- pb,
- False,
- [],
- False,
- False,
- None,
- False,
- None,
- False)
- assert not fm.start_client_playback(pb, False)
- fm.client_playback.testing = True
-
- assert not fm.state.flow_count()
- fm.tick(0)
- assert fm.state.flow_count()
-
- f.error = Error("error")
- fm.error(f)
-
- def test_server_playback(self):
- s = flow.State()
-
- f = tutils.tflow()
- f.response = HTTPResponse.wrap(netlib.tutils.tresp(content=f.request))
- pb = [f]
-
- fm = flow.FlowMaster(options.Options(), None, s)
- fm.refresh_server_playback = True
- assert not fm.do_server_playback(tutils.tflow())
-
- fm.start_server_playback(
- pb,
- False,
- [],
- False,
- False,
- None,
- False,
- None,
- False)
- assert fm.do_server_playback(tutils.tflow())
-
- fm.start_server_playback(
- pb,
- False,
- [],
- True,
- False,
- None,
- False,
- None,
- False)
- r = tutils.tflow()
- r.request.content = b"gibble"
- assert not fm.do_server_playback(r)
- assert fm.do_server_playback(tutils.tflow())
-
- fm.tick(0)
- assert fm.should_exit.is_set()
-
- fm.stop_server_playback()
- assert not fm.server_playback
-
- def test_server_playback_kill(self):
- s = flow.State()
- f = tutils.tflow()
- f.response = HTTPResponse.wrap(netlib.tutils.tresp(content=f.request))
- pb = [f]
- fm = flow.FlowMaster(None, None, s)
- fm.refresh_server_playback = True
- fm.start_server_playback(
- pb,
- True,
- [],
- False,
- False,
- None,
- False,
- None,
- False)
-
- f = tutils.tflow()
- f.request.host = "nonexistent"
- fm.request(f)
- assert f.reply.value == Kill
-
class TestRequest:
diff --git a/test/mitmproxy/test_fuzzing.py b/test/mitmproxy/test_fuzzing.py
index 27ea36a6..905ba1cd 100644
--- a/test/mitmproxy/test_fuzzing.py
+++ b/test/mitmproxy/test_fuzzing.py
@@ -11,17 +11,20 @@ class TestFuzzy(tservers.HTTPProxyTest):
def test_idna_err(self):
req = r'get:"http://localhost:%s":i10,"\xc6"'
p = self.pathoc()
- assert p.request(req % self.server.port).status_code == 400
+ with p.connect():
+ assert p.request(req % self.server.port).status_code == 400
def test_nullbytes(self):
req = r'get:"http://localhost:%s":i19,"\x00"'
p = self.pathoc()
- assert p.request(req % self.server.port).status_code == 400
+ with p.connect():
+ assert p.request(req % self.server.port).status_code == 400
def test_invalid_ipv6_url(self):
req = 'get:"http://localhost:%s":i13,"["'
p = self.pathoc()
- resp = p.request(req % self.server.port)
+ with p.connect():
+ resp = p.request(req % self.server.port)
assert resp.status_code == 400
# def test_invalid_upstream(self):
diff --git a/test/mitmproxy/test_server.py b/test/mitmproxy/test_server.py
index e0a8da47..c5a5bb71 100644
--- a/test/mitmproxy/test_server.py
+++ b/test/mitmproxy/test_server.py
@@ -60,7 +60,7 @@ class CommonMixin:
# Disconnect error
l.request.path = "/p/305:d0"
rt = self.master.replay_request(l, block=True)
- assert not rt
+ assert rt
if isinstance(self, tservers.HTTPUpstreamProxyTest):
assert l.response.status_code == 502
else:
@@ -72,7 +72,7 @@ class CommonMixin:
# In upstream mode with ssl, the replay will fail as we cannot establish
# SSL with the upstream proxy.
rt = self.master.replay_request(l, block=True)
- assert not rt
+ assert rt
if isinstance(self, tservers.HTTPUpstreamProxyTest):
assert l.response.status_code == 502
else:
@@ -91,11 +91,11 @@ class CommonMixin:
def test_invalid_http(self):
t = tcp.TCPClient(("127.0.0.1", self.proxy.port))
- t.connect()
- t.wfile.write(b"invalid\r\n\r\n")
- t.wfile.flush()
- line = t.rfile.readline()
- assert (b"Bad Request" in line) or (b"Bad Gateway" in line)
+ with t.connect():
+ t.wfile.write(b"invalid\r\n\r\n")
+ t.wfile.flush()
+ line = t.rfile.readline()
+ assert (b"Bad Request" in line) or (b"Bad Gateway" in line)
def test_sni(self):
if not self.ssl:
@@ -208,20 +208,22 @@ class TestHTTP(tservers.HTTPProxyTest, CommonMixin, AppMixin):
def test_app_err(self):
p = self.pathoc()
- ret = p.request("get:'http://errapp/'")
+ with p.connect():
+ ret = p.request("get:'http://errapp/'")
assert ret.status_code == 500
assert b"ValueError" in ret.content
def test_invalid_connect(self):
t = tcp.TCPClient(("127.0.0.1", self.proxy.port))
- t.connect()
- t.wfile.write(b"CONNECT invalid\n\n")
- t.wfile.flush()
- assert b"Bad Request" in t.rfile.readline()
+ with t.connect():
+ t.wfile.write(b"CONNECT invalid\n\n")
+ t.wfile.flush()
+ assert b"Bad Request" in t.rfile.readline()
def test_upstream_ssl_error(self):
p = self.pathoc()
- ret = p.request("get:'https://localhost:%s/'" % self.server.port)
+ with p.connect():
+ ret = p.request("get:'https://localhost:%s/'" % self.server.port)
assert ret.status_code == 400
def test_connection_close(self):
@@ -232,25 +234,28 @@ class TestHTTP(tservers.HTTPProxyTest, CommonMixin, AppMixin):
# Lets sanity check that the connection does indeed stay open by
# issuing two requests over the same connection
p = self.pathoc()
- assert p.request("get:'%s'" % response)
- assert p.request("get:'%s'" % response)
+ with p.connect():
+ assert p.request("get:'%s'" % response)
+ assert p.request("get:'%s'" % response)
# Now check that the connection is closed as the client specifies
p = self.pathoc()
- assert p.request("get:'%s':h'Connection'='close'" % response)
- # There's a race here, which means we can get any of a number of errors.
- # Rather than introduce yet another sleep into the test suite, we just
- # relax the Exception specification.
- with raises(Exception):
- p.request("get:'%s'" % response)
+ with p.connect():
+ assert p.request("get:'%s':h'Connection'='close'" % response)
+ # There's a race here, which means we can get any of a number of errors.
+ # Rather than introduce yet another sleep into the test suite, we just
+ # relax the Exception specification.
+ with raises(Exception):
+ p.request("get:'%s'" % response)
def test_reconnect(self):
req = "get:'%s/p/200:b@1:da'" % self.server.urlbase
p = self.pathoc()
- assert p.request(req)
- # Server has disconnected. Mitmproxy should detect this, and reconnect.
- assert p.request(req)
- assert p.request(req)
+ with p.connect():
+ assert p.request(req)
+ # Server has disconnected. Mitmproxy should detect this, and reconnect.
+ assert p.request(req)
+ assert p.request(req)
def test_get_connection_switching(self):
def switched(l):
@@ -260,18 +265,21 @@ class TestHTTP(tservers.HTTPProxyTest, CommonMixin, AppMixin):
req = "get:'%s/p/200:b@1'"
p = self.pathoc()
- assert p.request(req % self.server.urlbase)
- assert p.request(req % self.server2.urlbase)
+ with p.connect():
+ assert p.request(req % self.server.urlbase)
+ assert p.request(req % self.server2.urlbase)
assert switched(self.proxy.tlog)
def test_blank_leading_line(self):
p = self.pathoc()
- req = "get:'%s/p/201':i0,'\r\n'"
- assert p.request(req % self.server.urlbase).status_code == 201
+ with p.connect():
+ req = "get:'%s/p/201':i0,'\r\n'"
+ assert p.request(req % self.server.urlbase).status_code == 201
def test_invalid_headers(self):
p = self.pathoc()
- resp = p.request("get:'http://foo':h':foo'='bar'")
+ with p.connect():
+ resp = p.request("get:'http://foo':h':foo'='bar'")
assert resp.status_code == 400
def test_stream(self):
@@ -301,15 +309,16 @@ class TestHTTPAuth(tservers.HTTPProxyTest):
self.master.options.auth_singleuser = "test:test"
assert self.pathod("202").status_code == 407
p = self.pathoc()
- ret = p.request("""
- get
- 'http://localhost:%s/p/202'
- h'%s'='%s'
- """ % (
- self.server.port,
- http.authentication.BasicProxyAuth.AUTH_HEADER,
- authentication.assemble_http_basic_auth("basic", "test", "test")
- ))
+ with p.connect():
+ ret = p.request("""
+ get
+ 'http://localhost:%s/p/202'
+ h'%s'='%s'
+ """ % (
+ self.server.port,
+ http.authentication.BasicProxyAuth.AUTH_HEADER,
+ authentication.assemble_http_basic_auth("basic", "test", "test")
+ ))
assert ret.status_code == 202
@@ -318,14 +327,15 @@ class TestHTTPReverseAuth(tservers.ReverseProxyTest):
self.master.options.auth_singleuser = "test:test"
assert self.pathod("202").status_code == 401
p = self.pathoc()
- ret = p.request("""
- get
- '/p/202'
- h'%s'='%s'
- """ % (
- http.authentication.BasicWebsiteAuth.AUTH_HEADER,
- authentication.assemble_http_basic_auth("basic", "test", "test")
- ))
+ with p.connect():
+ ret = p.request("""
+ get
+ '/p/202'
+ h'%s'='%s'
+ """ % (
+ http.authentication.BasicWebsiteAuth.AUTH_HEADER,
+ authentication.assemble_http_basic_auth("basic", "test", "test")
+ ))
assert ret.status_code == 202
@@ -354,7 +364,8 @@ class TestHTTPS(tservers.HTTPProxyTest, CommonMixin, TcpMixin):
def test_error_post_connect(self):
p = self.pathoc()
- assert p.request("get:/:i0,'invalid\r\n\r\n'").status_code == 400
+ with p.connect():
+ assert p.request("get:/:i0,'invalid\r\n\r\n'").status_code == 400
class TestHTTPSCertfile(tservers.HTTPProxyTest, CommonMixin):
@@ -389,7 +400,8 @@ class TestHTTPSUpstreamServerVerificationWTrustedCert(tservers.HTTPProxyTest):
def _request(self):
p = self.pathoc(sni="example.mitmproxy.org")
- return p.request("get:/p/242")
+ with p.connect():
+ return p.request("get:/p/242")
def test_verification_w_cadir(self):
self.config.options.update(
@@ -426,7 +438,8 @@ class TestHTTPSUpstreamServerVerificationWBadCert(tservers.HTTPProxyTest):
def _request(self):
p = self.pathoc(sni="example.mitmproxy.org")
- return p.request("get:/p/242")
+ with p.connect():
+ return p.request("get:/p/242")
@classmethod
def get_options(cls):
@@ -481,13 +494,15 @@ class TestSocks5(tservers.SocksModeTest):
def test_simple(self):
p = self.pathoc()
- p.socks_connect(("localhost", self.server.port))
- f = p.request("get:/p/200")
+ with p.connect():
+ p.socks_connect(("localhost", self.server.port))
+ f = p.request("get:/p/200")
assert f.status_code == 200
def test_with_authentication_only(self):
p = self.pathoc()
- f = p.request("get:/p/200")
+ with p.connect():
+ f = p.request("get:/p/200")
assert f.status_code == 502
assert b"SOCKS5 mode failure" in f.content
@@ -496,21 +511,21 @@ class TestSocks5(tservers.SocksModeTest):
mitmproxy doesn't support UDP or BIND SOCKS CMDs
"""
p = self.pathoc()
-
- socks.ClientGreeting(
- socks.VERSION.SOCKS5,
- [socks.METHOD.NO_AUTHENTICATION_REQUIRED]
- ).to_file(p.wfile)
- socks.Message(
- socks.VERSION.SOCKS5,
- socks.CMD.BIND,
- socks.ATYP.DOMAINNAME,
- ("example.com", 8080)
- ).to_file(p.wfile)
-
- p.wfile.flush()
- p.rfile.read(2) # read server greeting
- f = p.request("get:/p/200") # the request doesn't matter, error response from handshake will be read anyway.
+ with p.connect():
+ socks.ClientGreeting(
+ socks.VERSION.SOCKS5,
+ [socks.METHOD.NO_AUTHENTICATION_REQUIRED]
+ ).to_file(p.wfile)
+ socks.Message(
+ socks.VERSION.SOCKS5,
+ socks.CMD.BIND,
+ socks.ATYP.DOMAINNAME,
+ ("example.com", 8080)
+ ).to_file(p.wfile)
+
+ p.wfile.flush()
+ p.rfile.read(2) # read server greeting
+ f = p.request("get:/p/200") # the request doesn't matter, error response from handshake will be read anyway.
assert f.status_code == 502
assert b"SOCKS5 mode failure" in f.content
@@ -531,21 +546,23 @@ class TestHttps2Http(tservers.ReverseProxyTest):
p = pathoc.Pathoc(
("localhost", self.proxy.port), ssl=True, sni=sni, fp=None
)
- p.connect()
return p
def test_all(self):
p = self.pathoc(ssl=True)
- assert p.request("get:'/p/200'").status_code == 200
+ with p.connect():
+ assert p.request("get:'/p/200'").status_code == 200
def test_sni(self):
p = self.pathoc(ssl=True, sni="example.com")
- assert p.request("get:'/p/200'").status_code == 200
- assert all("Error in handle_sni" not in msg for msg in self.proxy.tlog)
+ with p.connect():
+ assert p.request("get:'/p/200'").status_code == 200
+ assert all("Error in handle_sni" not in msg for msg in self.proxy.tlog)
def test_http(self):
p = self.pathoc(ssl=False)
- assert p.request("get:'/p/200'").status_code == 200
+ with p.connect():
+ assert p.request("get:'/p/200'").status_code == 200
class TestTransparent(tservers.TransparentProxyTest, CommonMixin, TcpMixin):
@@ -703,29 +720,29 @@ class TestRedirectRequest(tservers.HTTPProxyTest):
self.master.redirect_port = self.server2.port
p = self.pathoc()
-
- self.server.clear_log()
- self.server2.clear_log()
- r1 = p.request("get:'/p/200'")
- assert r1.status_code == 200
- assert self.server.last_log()
- assert not self.server2.last_log()
-
- self.server.clear_log()
- self.server2.clear_log()
- r2 = p.request("get:'/p/201'")
- assert r2.status_code == 201
- assert not self.server.last_log()
- assert self.server2.last_log()
-
- self.server.clear_log()
- self.server2.clear_log()
- r3 = p.request("get:'/p/202'")
- assert r3.status_code == 202
- assert self.server.last_log()
- assert not self.server2.last_log()
-
- assert r1.content == r2.content == r3.content
+ with p.connect():
+ self.server.clear_log()
+ self.server2.clear_log()
+ r1 = p.request("get:'/p/200'")
+ assert r1.status_code == 200
+ assert self.server.last_log()
+ assert not self.server2.last_log()
+
+ self.server.clear_log()
+ self.server2.clear_log()
+ r2 = p.request("get:'/p/201'")
+ assert r2.status_code == 201
+ assert not self.server.last_log()
+ assert self.server2.last_log()
+
+ self.server.clear_log()
+ self.server2.clear_log()
+ r3 = p.request("get:'/p/202'")
+ assert r3.status_code == 202
+ assert self.server.last_log()
+ assert not self.server2.last_log()
+
+ assert r1.content == r2.content == r3.content
class MasterStreamRequest(tservers.TestMaster):
@@ -743,22 +760,22 @@ class TestStreamRequest(tservers.HTTPProxyTest):
def test_stream_simple(self):
p = self.pathoc()
-
- # a request with 100k of data but without content-length
- r1 = p.request("get:'%s/p/200:r:b@100k:d102400'" % self.server.urlbase)
- assert r1.status_code == 200
- assert len(r1.content) > 100000
+ with p.connect():
+ # a request with 100k of data but without content-length
+ r1 = p.request("get:'%s/p/200:r:b@100k:d102400'" % self.server.urlbase)
+ assert r1.status_code == 200
+ assert len(r1.content) > 100000
def test_stream_multiple(self):
p = self.pathoc()
+ with p.connect():
+ # simple request with streaming turned on
+ r1 = p.request("get:'%s/p/200'" % self.server.urlbase)
+ assert r1.status_code == 200
- # simple request with streaming turned on
- r1 = p.request("get:'%s/p/200'" % self.server.urlbase)
- assert r1.status_code == 200
-
- # now send back 100k of data, streamed but not chunked
- r1 = p.request("get:'%s/p/201:b@100k'" % self.server.urlbase)
- assert r1.status_code == 201
+ # now send back 100k of data, streamed but not chunked
+ r1 = p.request("get:'%s/p/201:b@100k'" % self.server.urlbase)
+ assert r1.status_code == 201
def test_stream_chunked(self):
connection = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
@@ -887,7 +904,8 @@ class TestUpstreamProxy(tservers.HTTPUpstreamProxyTest, CommonMixin, AppMixin):
("~s", "baz", "ORLY")
]
p = self.pathoc()
- req = p.request("get:'%s/p/418:b\"foo\"'" % self.server.urlbase)
+ with p.connect():
+ req = p.request("get:'%s/p/418:b\"foo\"'" % self.server.urlbase)
assert req.content == b"ORLY"
assert req.status_code == 418
@@ -948,7 +966,8 @@ class TestUpstreamProxySSL(
def test_simple(self):
p = self.pathoc()
- req = p.request("get:'/p/418:b\"content\"'")
+ with p.connect():
+ req = p.request("get:'/p/418:b\"content\"'")
assert req.content == b"content"
assert req.status_code == 418
@@ -1006,48 +1025,49 @@ class TestProxyChainingSSLReconnect(tservers.HTTPUpstreamProxyTest):
])
p = self.pathoc()
- req = p.request("get:'/p/418:b\"content\"'")
- assert req.content == b"content"
- assert req.status_code == 418
-
- assert self.proxy.tmaster.state.flow_count() == 2 # CONNECT and request
- # CONNECT, failing request,
- assert self.chain[0].tmaster.state.flow_count() == 4
- # reCONNECT, request
- # failing request, request
- assert self.chain[1].tmaster.state.flow_count() == 2
- # (doesn't store (repeated) CONNECTs from chain[0]
- # as it is a regular proxy)
-
- assert not self.chain[1].tmaster.state.flows[0].response # killed
- assert self.chain[1].tmaster.state.flows[1].response
-
- assert self.proxy.tmaster.state.flows[0].request.first_line_format == "authority"
- assert self.proxy.tmaster.state.flows[1].request.first_line_format == "relative"
-
- assert self.chain[0].tmaster.state.flows[
- 0].request.first_line_format == "authority"
- assert self.chain[0].tmaster.state.flows[
- 1].request.first_line_format == "relative"
- assert self.chain[0].tmaster.state.flows[
- 2].request.first_line_format == "authority"
- assert self.chain[0].tmaster.state.flows[
- 3].request.first_line_format == "relative"
-
- assert self.chain[1].tmaster.state.flows[
- 0].request.first_line_format == "relative"
- assert self.chain[1].tmaster.state.flows[
- 1].request.first_line_format == "relative"
-
- req = p.request("get:'/p/418:b\"content2\"'")
-
- assert req.status_code == 502
- assert self.proxy.tmaster.state.flow_count() == 3 # + new request
- # + new request, repeated CONNECT from chain[1]
- assert self.chain[0].tmaster.state.flow_count() == 6
- # (both terminated)
- # nothing happened here
- assert self.chain[1].tmaster.state.flow_count() == 2
+ with p.connect():
+ req = p.request("get:'/p/418:b\"content\"'")
+ assert req.content == b"content"
+ assert req.status_code == 418
+
+ assert self.proxy.tmaster.state.flow_count() == 2 # CONNECT and request
+ # CONNECT, failing request,
+ assert self.chain[0].tmaster.state.flow_count() == 4
+ # reCONNECT, request
+ # failing request, request
+ assert self.chain[1].tmaster.state.flow_count() == 2
+ # (doesn't store (repeated) CONNECTs from chain[0]
+ # as it is a regular proxy)
+
+ assert not self.chain[1].tmaster.state.flows[0].response # killed
+ assert self.chain[1].tmaster.state.flows[1].response
+
+ assert self.proxy.tmaster.state.flows[0].request.first_line_format == "authority"
+ assert self.proxy.tmaster.state.flows[1].request.first_line_format == "relative"
+
+ assert self.chain[0].tmaster.state.flows[
+ 0].request.first_line_format == "authority"
+ assert self.chain[0].tmaster.state.flows[
+ 1].request.first_line_format == "relative"
+ assert self.chain[0].tmaster.state.flows[
+ 2].request.first_line_format == "authority"
+ assert self.chain[0].tmaster.state.flows[
+ 3].request.first_line_format == "relative"
+
+ assert self.chain[1].tmaster.state.flows[
+ 0].request.first_line_format == "relative"
+ assert self.chain[1].tmaster.state.flows[
+ 1].request.first_line_format == "relative"
+
+ req = p.request("get:'/p/418:b\"content2\"'")
+
+ assert req.status_code == 502
+ assert self.proxy.tmaster.state.flow_count() == 3 # + new request
+ # + new request, repeated CONNECT from chain[1]
+ assert self.chain[0].tmaster.state.flow_count() == 6
+ # (both terminated)
+ # nothing happened here
+ assert self.chain[1].tmaster.state.flow_count() == 2
class AddUpstreamCertsToClientChainMixin:
@@ -1066,12 +1086,13 @@ class AddUpstreamCertsToClientChainMixin:
d = f.read()
upstreamCert = SSLCert.from_pem(d)
p = self.pathoc()
- upstream_cert_found_in_client_chain = False
- for receivedCert in p.server_certs:
- if receivedCert.digest('sha256') == upstreamCert.digest('sha256'):
- upstream_cert_found_in_client_chain = True
- break
- assert(upstream_cert_found_in_client_chain == self.master.options.add_upstream_certs_to_client_chain)
+ with p.connect():
+ upstream_cert_found_in_client_chain = False
+ for receivedCert in p.server_certs:
+ if receivedCert.digest('sha256') == upstreamCert.digest('sha256'):
+ upstream_cert_found_in_client_chain = True
+ break
+ assert(upstream_cert_found_in_client_chain == self.master.options.add_upstream_certs_to_client_chain)
class TestHTTPSAddUpstreamCertsToClientChainTrue(
diff --git a/test/mitmproxy/tservers.py b/test/mitmproxy/tservers.py
index 1597f59c..4291f743 100644
--- a/test/mitmproxy/tservers.py
+++ b/test/mitmproxy/tservers.py
@@ -3,6 +3,7 @@ import threading
import tempfile
import flask
import mock
+import sys
from mitmproxy.proxy.config import ProxyConfig
from mitmproxy.proxy.server import ProxyServer
@@ -10,6 +11,7 @@ import pathod.test
import pathod.pathoc
from mitmproxy import flow, controller, options
from mitmproxy import builtins
+import netlib.exceptions
testapp = flask.Flask(__name__)
@@ -104,6 +106,14 @@ class ProxyTestBase(object):
cls.server.shutdown()
cls.server2.shutdown()
+ def teardown(self):
+ try:
+ self.server.wait_for_silence()
+ except netlib.exceptions.Timeout:
+ # FIXME: Track down the Windows sync issues
+ if sys.platform != "win32":
+ raise
+
def setup(self):
self.master.clear_log()
self.master.state.clear()
@@ -125,6 +135,15 @@ class ProxyTestBase(object):
)
+class LazyPathoc(pathod.pathoc.Pathoc):
+ def __init__(self, lazy_connect, *args, **kwargs):
+ self.lazy_connect = lazy_connect
+ pathod.pathoc.Pathoc.__init__(self, *args, **kwargs)
+
+ def connect(self):
+ return pathod.pathoc.Pathoc.connect(self, self.lazy_connect)
+
+
class HTTPProxyTest(ProxyTestBase):
def pathoc_raw(self):
@@ -134,14 +153,14 @@ class HTTPProxyTest(ProxyTestBase):
"""
Returns a connected Pathoc instance.
"""
- p = pathod.pathoc.Pathoc(
- ("localhost", self.proxy.port), ssl=self.ssl, sni=sni, fp=None
- )
if self.ssl:
- p.connect(("127.0.0.1", self.server.port))
+ conn = ("127.0.0.1", self.server.port)
else:
- p.connect()
- return p
+ conn = None
+ return LazyPathoc(
+ conn,
+ ("localhost", self.proxy.port), ssl=self.ssl, sni=sni, fp=None
+ )
def pathod(self, spec, sni=None):
"""
@@ -152,18 +171,20 @@ class HTTPProxyTest(ProxyTestBase):
q = "get:'/p/%s'" % spec
else:
q = "get:'%s/p/%s'" % (self.server.urlbase, spec)
- return p.request(q)
+ with p.connect():
+ return p.request(q)
def app(self, page):
if self.ssl:
p = pathod.pathoc.Pathoc(
("127.0.0.1", self.proxy.port), True, fp=None
)
- p.connect((options.APP_HOST, options.APP_PORT))
- return p.request("get:'%s'" % page)
+ with p.connect((options.APP_HOST, options.APP_PORT)):
+ return p.request("get:'%s'" % page)
else:
p = self.pathoc()
- return p.request("get:'http://%s%s'" % (options.APP_HOST, page))
+ with p.connect():
+ return p.request("get:'http://%s%s'" % (options.APP_HOST, page))
class TResolver:
@@ -210,7 +231,8 @@ class TransparentProxyTest(ProxyTestBase):
else:
p = self.pathoc()
q = "get:'/p/%s'" % spec
- return p.request(q)
+ with p.connect():
+ return p.request(q)
def pathoc(self, sni=None):
"""
@@ -219,7 +241,6 @@ class TransparentProxyTest(ProxyTestBase):
p = pathod.pathoc.Pathoc(
("localhost", self.proxy.port), ssl=self.ssl, sni=sni, fp=None
)
- p.connect()
return p
@@ -247,7 +268,6 @@ class ReverseProxyTest(ProxyTestBase):
p = pathod.pathoc.Pathoc(
("localhost", self.proxy.port), ssl=self.ssl, sni=sni, fp=None
)
- p.connect()
return p
def pathod(self, spec, sni=None):
@@ -260,7 +280,8 @@ class ReverseProxyTest(ProxyTestBase):
else:
p = self.pathoc()
q = "get:'/p/%s'" % spec
- return p.request(q)
+ with p.connect():
+ return p.request(q)
class SocksModeTest(HTTPProxyTest):
diff --git a/test/netlib/http/test_headers.py b/test/netlib/http/test_headers.py
index ad2bc548..e8752c52 100644
--- a/test/netlib/http/test_headers.py
+++ b/test/netlib/http/test_headers.py
@@ -43,6 +43,15 @@ class TestHeaders(object):
with raises(TypeError):
Headers([[b"Host", u"not-bytes"]])
+ def test_set(self):
+ headers = Headers()
+ headers[u"foo"] = u"1"
+ headers[b"bar"] = b"2"
+ headers["baz"] = b"3"
+ with raises(TypeError):
+ headers["foobar"] = 42
+ assert len(headers) == 3
+
def test_bytes(self):
headers = Headers(Host="example.com")
assert bytes(headers) == b"Host: example.com\r\n"
diff --git a/test/netlib/http/test_response.py b/test/netlib/http/test_response.py
index c7b1b646..e97cc419 100644
--- a/test/netlib/http/test_response.py
+++ b/test/netlib/http/test_response.py
@@ -34,6 +34,11 @@ class TestResponseCore(object):
assert r.status_code == 200
assert r.content == b""
+ r = Response.make(418, "teatime")
+ assert r.status_code == 418
+ assert r.content == b"teatime"
+ assert r.headers["content-length"] == "7"
+
Response.make(content=b"foo")
Response.make(content="foo")
with raises(TypeError):
diff --git a/test/netlib/test_encoding.py b/test/netlib/test_encoding.py
index 08e69ec5..e1175ef0 100644
--- a/test/netlib/test_encoding.py
+++ b/test/netlib/test_encoding.py
@@ -1,55 +1,46 @@
import mock
+import pytest
+
from netlib import encoding, tutils
-def test_identity():
- assert b"string" == encoding.decode(b"string", "identity")
- assert b"string" == encoding.encode(b"string", "identity")
+@pytest.mark.parametrize("encoder", [
+ 'identity',
+ 'none',
+])
+def test_identity(encoder):
+ assert b"string" == encoding.decode(b"string", encoder)
+ assert b"string" == encoding.encode(b"string", encoder)
with tutils.raises(ValueError):
encoding.encode(b"string", "nonexistent encoding")
-def test_gzip():
- assert b"string" == encoding.decode(
- encoding.encode(
- b"string",
- "gzip"
- ),
- "gzip"
- )
- with tutils.raises(ValueError):
- encoding.decode(b"bogus", "gzip")
+@pytest.mark.parametrize("encoder", [
+ 'gzip',
+ 'br',
+ 'deflate',
+])
+def test_encoders(encoder):
+ assert "" == encoding.decode("", encoder)
+ assert b"" == encoding.decode(b"", encoder)
-
-def test_brotli():
- assert b"string" == encoding.decode(
+ assert "string" == encoding.decode(
encoding.encode(
- b"string",
- "br"
+ "string",
+ encoder
),
- "br"
+ encoder
)
- with tutils.raises(ValueError):
- encoding.decode(b"bogus", "br")
-
-
-def test_deflate():
assert b"string" == encoding.decode(
encoding.encode(
b"string",
- "deflate"
+ encoder
),
- "deflate"
- )
- assert b"string" == encoding.decode(
- encoding.encode(
- b"string",
- "deflate"
- )[2:-4],
- "deflate"
+ encoder
)
+
with tutils.raises(ValueError):
- encoding.decode(b"bogus", "deflate")
+ encoding.decode(b"foobar", encoder)
def test_cache():
diff --git a/test/netlib/test_strutils.py b/test/netlib/test_strutils.py
index 5be254a3..0f58cac5 100644
--- a/test/netlib/test_strutils.py
+++ b/test/netlib/test_strutils.py
@@ -8,6 +8,8 @@ def test_always_bytes():
assert strutils.always_bytes("foo") == b"foo"
with tutils.raises(ValueError):
strutils.always_bytes(u"\u2605", "ascii")
+ with tutils.raises(TypeError):
+ strutils.always_bytes(42, "ascii")
def test_native():
diff --git a/test/pathod/test_protocols_http2.py b/test/pathod/test_protocols_http2.py
index 8d7efc82..7f65c0eb 100644
--- a/test/pathod/test_protocols_http2.py
+++ b/test/pathod/test_protocols_http2.py
@@ -5,7 +5,7 @@ import hyperframe
from netlib import tcp, http
from netlib.tutils import raises
from netlib.exceptions import TcpDisconnect
-from netlib.http.http2 import framereader
+from netlib.http import http2
from ..netlib import tservers as netlib_tservers
@@ -112,11 +112,11 @@ class TestPerformServerConnectionPreface(netlib_tservers.ServerTestBase):
self.wfile.flush()
# check empty settings frame
- raw = framereader.http2_read_raw_frame(self.rfile)
+ raw = http2.read_raw_frame(self.rfile)
assert raw == codecs.decode('00000c040000000000000200000000000300000001', 'hex_codec')
# check settings acknowledgement
- raw = framereader.http2_read_raw_frame(self.rfile)
+ raw = http2.read_raw_frame(self.rfile)
assert raw == codecs.decode('000000040100000000', 'hex_codec')
# send settings acknowledgement