2011-02-16 21:18:38 +00:00
|
|
|
import os
|
2011-02-16 09:10:24 +00:00
|
|
|
from cStringIO import StringIO
|
2015-09-11 17:03:50 +00:00
|
|
|
from libmproxy.exceptions import ContentViewException
|
2015-08-30 13:27:29 +00:00
|
|
|
from libmproxy.models import HTTPResponse
|
2015-07-29 09:39:53 +00:00
|
|
|
|
2015-08-01 08:40:19 +00:00
|
|
|
import netlib.tutils
|
2015-09-16 16:45:22 +00:00
|
|
|
from netlib.http import CONTENT_MISSING
|
2015-07-29 09:39:53 +00:00
|
|
|
|
2014-11-05 21:35:00 +00:00
|
|
|
from libmproxy import dump, flow
|
2015-09-03 15:01:25 +00:00
|
|
|
from libmproxy.proxy import Log
|
2011-03-05 02:58:48 +00:00
|
|
|
import tutils
|
2013-02-16 23:42:48 +00:00
|
|
|
import mock
|
2011-02-16 09:10:24 +00:00
|
|
|
|
2014-11-05 21:35:00 +00:00
|
|
|
|
2012-06-09 01:42:43 +00:00
|
|
|
def test_strfuncs():
|
2015-09-11 17:03:50 +00:00
|
|
|
o = dump.Options()
|
|
|
|
m = dump.DumpMaster(None, o)
|
|
|
|
|
|
|
|
m.outfile = StringIO()
|
|
|
|
m.o.flow_detail = 0
|
|
|
|
m.echo_flow(tutils.tflow())
|
|
|
|
assert not m.outfile.getvalue()
|
|
|
|
|
|
|
|
m.o.flow_detail = 4
|
|
|
|
m.echo_flow(tutils.tflow())
|
|
|
|
assert m.outfile.getvalue()
|
|
|
|
|
|
|
|
m.outfile = StringIO()
|
|
|
|
m.echo_flow(tutils.tflow(resp=True))
|
|
|
|
assert "<<" in m.outfile.getvalue()
|
|
|
|
|
|
|
|
m.outfile = StringIO()
|
|
|
|
m.echo_flow(tutils.tflow(err=True))
|
|
|
|
assert "<<" in m.outfile.getvalue()
|
|
|
|
|
|
|
|
flow = tutils.tflow()
|
|
|
|
flow.request = netlib.tutils.treq()
|
|
|
|
flow.request.stickycookie = True
|
|
|
|
flow.client_conn = mock.MagicMock()
|
|
|
|
flow.client_conn.address.host = "foo"
|
2015-09-16 16:45:22 +00:00
|
|
|
flow.response = netlib.tutils.tresp(body=CONTENT_MISSING)
|
2015-09-11 17:03:50 +00:00
|
|
|
flow.response.is_replay = True
|
2015-09-17 13:16:33 +00:00
|
|
|
flow.response.status_code = 300
|
2015-09-11 17:03:50 +00:00
|
|
|
m.echo_flow(flow)
|
|
|
|
|
|
|
|
|
2015-09-16 16:45:22 +00:00
|
|
|
flow = tutils.tflow(resp=netlib.tutils.tresp(body="{"))
|
2015-09-11 17:03:50 +00:00
|
|
|
flow.response.headers["content-type"] = "application/json"
|
2015-09-17 13:16:33 +00:00
|
|
|
flow.response.status_code = 400
|
2015-09-11 17:03:50 +00:00
|
|
|
m.echo_flow(flow)
|
|
|
|
|
|
|
|
|
2015-09-12 11:49:16 +00:00
|
|
|
@mock.patch("libmproxy.contentviews.get_content_view")
|
2015-09-11 17:03:50 +00:00
|
|
|
def test_contentview(get_content_view):
|
2015-09-12 15:40:30 +00:00
|
|
|
get_content_view.side_effect = ContentViewException(""), ("x", iter([]))
|
2015-09-11 17:03:50 +00:00
|
|
|
|
|
|
|
o = dump.Options(flow_detail=4, verbosity=3)
|
|
|
|
m = dump.DumpMaster(None, o, StringIO())
|
|
|
|
m.echo_flow(tutils.tflow())
|
|
|
|
assert "Content viewer failed" in m.outfile.getvalue()
|
2011-02-25 08:23:44 +00:00
|
|
|
|
2011-02-16 09:10:24 +00:00
|
|
|
|
2012-06-09 01:42:43 +00:00
|
|
|
class TestDumpMaster:
|
2011-02-19 20:55:42 +00:00
|
|
|
def _cycle(self, m, content):
|
2015-09-16 16:45:22 +00:00
|
|
|
f = tutils.tflow(req=netlib.tutils.treq(body=content))
|
2014-03-09 20:51:24 +00:00
|
|
|
l = Log("connect")
|
2013-02-16 23:42:48 +00:00
|
|
|
l.reply = mock.MagicMock()
|
2012-07-01 00:10:32 +00:00
|
|
|
m.handle_log(l)
|
2014-09-03 14:57:56 +00:00
|
|
|
m.handle_clientconnect(f.client_conn)
|
|
|
|
m.handle_serverconnect(f.server_conn)
|
|
|
|
m.handle_request(f)
|
2015-09-16 16:45:22 +00:00
|
|
|
f.response = HTTPResponse.wrap(netlib.tutils.tresp(body=content))
|
2014-09-03 14:57:56 +00:00
|
|
|
f = m.handle_response(f)
|
|
|
|
m.handle_clientdisconnect(f.client_conn)
|
2012-04-02 21:52:26 +00:00
|
|
|
return f
|
2011-02-16 09:10:24 +00:00
|
|
|
|
2011-08-02 04:52:47 +00:00
|
|
|
def _dummy_cycle(self, n, filt, content, **options):
|
2011-02-17 23:40:45 +00:00
|
|
|
cs = StringIO()
|
2014-09-08 21:34:43 +00:00
|
|
|
o = dump.Options(filtstr=filt, **options)
|
|
|
|
m = dump.DumpMaster(None, o, outfile=cs)
|
2011-08-02 04:52:47 +00:00
|
|
|
for i in range(n):
|
|
|
|
self._cycle(m, content)
|
2013-06-17 14:48:06 +00:00
|
|
|
m.shutdown()
|
2011-02-17 23:40:45 +00:00
|
|
|
return cs.getvalue()
|
|
|
|
|
2011-08-02 04:52:47 +00:00
|
|
|
def _flowfile(self, path):
|
2013-06-15 22:23:44 +00:00
|
|
|
f = open(path, "wb")
|
2011-08-02 04:52:47 +00:00
|
|
|
fw = flow.FlowWriter(f)
|
2014-09-03 14:57:56 +00:00
|
|
|
t = tutils.tflow(resp=True)
|
2011-08-02 04:52:47 +00:00
|
|
|
fw.add(t)
|
|
|
|
f.close()
|
|
|
|
|
2013-01-05 08:41:16 +00:00
|
|
|
def test_error(self):
|
|
|
|
cs = StringIO()
|
2014-03-13 00:22:12 +00:00
|
|
|
o = dump.Options(flow_detail=1)
|
2014-09-08 21:34:43 +00:00
|
|
|
m = dump.DumpMaster(None, o, outfile=cs)
|
2014-09-03 14:57:56 +00:00
|
|
|
f = tutils.tflow(err=True)
|
|
|
|
m.handle_request(f)
|
|
|
|
assert m.handle_error(f)
|
2013-01-05 08:41:16 +00:00
|
|
|
assert "error" in cs.getvalue()
|
|
|
|
|
2014-11-05 21:35:00 +00:00
|
|
|
def test_missing_content(self):
|
|
|
|
cs = StringIO()
|
|
|
|
o = dump.Options(flow_detail=3)
|
|
|
|
m = dump.DumpMaster(None, o, outfile=cs)
|
|
|
|
f = tutils.tflow()
|
2015-07-29 09:39:53 +00:00
|
|
|
f.request.content = CONTENT_MISSING
|
2014-11-05 21:35:00 +00:00
|
|
|
m.handle_request(f)
|
2015-08-30 13:27:29 +00:00
|
|
|
f.response = HTTPResponse.wrap(netlib.tutils.tresp())
|
2015-07-29 09:39:53 +00:00
|
|
|
f.response.content = CONTENT_MISSING
|
2014-11-05 21:35:00 +00:00
|
|
|
m.handle_response(f)
|
|
|
|
assert "content missing" in cs.getvalue()
|
|
|
|
|
2011-02-20 20:54:39 +00:00
|
|
|
def test_replay(self):
|
|
|
|
cs = StringIO()
|
|
|
|
|
2015-02-05 13:44:45 +00:00
|
|
|
o = dump.Options(server_replay=["nonexistent"], kill=True)
|
2014-09-08 21:34:43 +00:00
|
|
|
tutils.raises(dump.DumpError, dump.DumpMaster, None, o, outfile=cs)
|
2011-02-20 20:54:39 +00:00
|
|
|
|
2012-06-09 01:42:43 +00:00
|
|
|
with tutils.tmpdir() as t:
|
|
|
|
p = os.path.join(t, "rep")
|
|
|
|
self._flowfile(p)
|
2011-02-20 20:54:39 +00:00
|
|
|
|
2015-01-05 21:12:38 +00:00
|
|
|
o = dump.Options(server_replay=[p], kill=True)
|
2014-09-08 21:34:43 +00:00
|
|
|
m = dump.DumpMaster(None, o, outfile=cs)
|
2012-02-10 02:04:20 +00:00
|
|
|
|
2012-06-09 01:42:43 +00:00
|
|
|
self._cycle(m, "content")
|
|
|
|
self._cycle(m, "content")
|
2011-02-20 22:08:35 +00:00
|
|
|
|
2015-01-05 21:12:38 +00:00
|
|
|
o = dump.Options(server_replay=[p], kill=False)
|
2014-09-08 21:34:43 +00:00
|
|
|
m = dump.DumpMaster(None, o, outfile=cs)
|
2012-06-09 01:42:43 +00:00
|
|
|
self._cycle(m, "nonexistent")
|
2011-02-20 20:54:39 +00:00
|
|
|
|
2015-01-05 21:12:38 +00:00
|
|
|
o = dump.Options(client_replay=[p], kill=False)
|
2014-09-08 21:34:43 +00:00
|
|
|
m = dump.DumpMaster(None, o, outfile=cs)
|
2011-03-06 03:02:28 +00:00
|
|
|
|
2011-08-02 04:52:47 +00:00
|
|
|
def test_read(self):
|
2012-06-09 01:42:43 +00:00
|
|
|
with tutils.tmpdir() as t:
|
|
|
|
p = os.path.join(t, "read")
|
|
|
|
self._flowfile(p)
|
2015-01-02 00:26:22 +00:00
|
|
|
assert "GET" in self._dummy_cycle(
|
|
|
|
0,
|
|
|
|
None,
|
|
|
|
"",
|
|
|
|
flow_detail=1,
|
|
|
|
rfile=p
|
|
|
|
)
|
2011-08-02 04:52:47 +00:00
|
|
|
|
2013-03-03 09:03:27 +00:00
|
|
|
tutils.raises(
|
2012-06-09 01:42:43 +00:00
|
|
|
dump.DumpError, self._dummy_cycle,
|
|
|
|
0, None, "", verbosity=1, rfile="/nonexistent"
|
|
|
|
)
|
2015-01-02 00:26:22 +00:00
|
|
|
tutils.raises(
|
|
|
|
dump.DumpError, self._dummy_cycle,
|
|
|
|
0, None, "", verbosity=1, rfile="test_dump.py"
|
|
|
|
)
|
2011-08-02 04:52:47 +00:00
|
|
|
|
2011-02-16 10:03:46 +00:00
|
|
|
def test_options(self):
|
|
|
|
o = dump.Options(verbosity = 2)
|
|
|
|
assert o.verbosity == 2
|
|
|
|
|
2011-02-16 21:44:08 +00:00
|
|
|
def test_filter(self):
|
2011-08-02 04:52:47 +00:00
|
|
|
assert not "GET" in self._dummy_cycle(1, "~u foo", "", verbosity=1)
|
2011-02-16 21:44:08 +00:00
|
|
|
|
2013-07-23 22:32:56 +00:00
|
|
|
def test_app(self):
|
|
|
|
o = dump.Options(app=True)
|
|
|
|
s = mock.MagicMock()
|
2014-09-08 21:34:43 +00:00
|
|
|
m = dump.DumpMaster(s, o)
|
2014-01-04 01:35:11 +00:00
|
|
|
assert len(m.apps.apps) == 1
|
2013-07-23 22:32:56 +00:00
|
|
|
|
2012-04-02 21:52:26 +00:00
|
|
|
def test_replacements(self):
|
2015-03-19 05:10:21 +00:00
|
|
|
cs = StringIO()
|
2012-04-02 21:52:26 +00:00
|
|
|
o = dump.Options(replacements=[(".*", "content", "foo")])
|
2015-03-19 05:10:21 +00:00
|
|
|
m = dump.DumpMaster(None, o, outfile=cs)
|
2012-04-02 21:52:26 +00:00
|
|
|
f = self._cycle(m, "content")
|
|
|
|
assert f.request.content == "foo"
|
|
|
|
|
2012-08-18 12:22:42 +00:00
|
|
|
def test_setheader(self):
|
2015-03-19 05:10:21 +00:00
|
|
|
cs = StringIO()
|
2012-08-18 12:22:42 +00:00
|
|
|
o = dump.Options(setheaders=[(".*", "one", "two")])
|
2015-03-19 05:10:21 +00:00
|
|
|
m = dump.DumpMaster(None, o, outfile=cs)
|
2012-08-18 12:22:42 +00:00
|
|
|
f = self._cycle(m, "content")
|
2015-09-05 18:45:58 +00:00
|
|
|
assert f.request.headers["one"] == "two"
|
2012-08-18 12:22:42 +00:00
|
|
|
|
2011-02-16 21:44:08 +00:00
|
|
|
def test_basic(self):
|
2011-02-16 09:10:24 +00:00
|
|
|
for i in (1, 2, 3):
|
2014-03-13 00:22:12 +00:00
|
|
|
assert "GET" in self._dummy_cycle(1, "~s", "", flow_detail=i)
|
2015-05-30 00:03:28 +00:00
|
|
|
assert "GET" in self._dummy_cycle(
|
|
|
|
1,
|
|
|
|
"~s",
|
|
|
|
"\x00\x00\x00",
|
|
|
|
flow_detail=i)
|
2014-03-13 00:22:12 +00:00
|
|
|
assert "GET" in self._dummy_cycle(1, "~s", "ascii", flow_detail=i)
|
2011-02-16 09:10:24 +00:00
|
|
|
|
2011-02-16 21:18:38 +00:00
|
|
|
def test_write(self):
|
2012-06-09 01:42:43 +00:00
|
|
|
with tutils.tmpdir() as d:
|
|
|
|
p = os.path.join(d, "a")
|
2015-05-30 00:03:28 +00:00
|
|
|
self._dummy_cycle(1, None, "", outfile=(p, "wb"), verbosity=0)
|
|
|
|
assert len(list(flow.FlowReader(open(p, "rb")).stream())) == 1
|
2011-02-16 21:18:38 +00:00
|
|
|
|
2014-12-11 18:21:33 +00:00
|
|
|
def test_write_append(self):
|
|
|
|
with tutils.tmpdir() as d:
|
|
|
|
p = os.path.join(d, "a.append")
|
2015-05-30 00:03:28 +00:00
|
|
|
self._dummy_cycle(1, None, "", outfile=(p, "wb"), verbosity=0)
|
|
|
|
self._dummy_cycle(1, None, "", outfile=(p, "ab"), verbosity=0)
|
|
|
|
assert len(list(flow.FlowReader(open(p, "rb")).stream())) == 2
|
2014-12-11 18:21:33 +00:00
|
|
|
|
2011-02-16 21:18:38 +00:00
|
|
|
def test_write_err(self):
|
2013-03-03 09:03:27 +00:00
|
|
|
tutils.raises(
|
2011-02-17 23:40:45 +00:00
|
|
|
dump.DumpError,
|
|
|
|
self._dummy_cycle,
|
2011-08-02 04:52:47 +00:00
|
|
|
1,
|
2011-02-17 23:40:45 +00:00
|
|
|
None,
|
2012-02-10 02:04:20 +00:00
|
|
|
"",
|
2014-12-11 18:21:33 +00:00
|
|
|
outfile = ("nonexistentdir/foo", "wb")
|
2011-02-17 23:40:45 +00:00
|
|
|
)
|
|
|
|
|
2011-08-03 04:36:20 +00:00
|
|
|
def test_script(self):
|
|
|
|
ret = self._dummy_cycle(
|
|
|
|
1, None, "",
|
2014-03-13 00:22:12 +00:00
|
|
|
scripts=[tutils.test_data.path("scripts/all.py")], verbosity=1
|
2011-02-17 23:40:45 +00:00
|
|
|
)
|
2011-08-03 04:36:20 +00:00
|
|
|
assert "XCLIENTCONNECT" in ret
|
2013-12-16 21:10:06 +00:00
|
|
|
assert "XSERVERCONNECT" in ret
|
2011-08-03 04:36:20 +00:00
|
|
|
assert "XREQUEST" in ret
|
|
|
|
assert "XRESPONSE" in ret
|
|
|
|
assert "XCLIENTDISCONNECT" in ret
|
2013-03-03 09:03:27 +00:00
|
|
|
tutils.raises(
|
2011-02-17 23:40:45 +00:00
|
|
|
dump.DumpError,
|
2014-01-12 10:01:59 +00:00
|
|
|
self._dummy_cycle, 1, None, "", scripts=["nonexistent"]
|
2011-02-17 23:40:45 +00:00
|
|
|
)
|
2013-03-03 09:03:27 +00:00
|
|
|
tutils.raises(
|
2011-02-17 23:40:45 +00:00
|
|
|
dump.DumpError,
|
2014-01-12 10:01:59 +00:00
|
|
|
self._dummy_cycle, 1, None, "", scripts=["starterr.py"]
|
2011-02-16 21:18:38 +00:00
|
|
|
)
|
|
|
|
|
2011-02-25 08:11:44 +00:00
|
|
|
def test_stickycookie(self):
|
2011-08-03 22:34:34 +00:00
|
|
|
self._dummy_cycle(1, None, "", stickycookie = ".*")
|
2011-02-25 08:11:44 +00:00
|
|
|
|
2011-03-20 05:52:16 +00:00
|
|
|
def test_stickyauth(self):
|
2011-08-03 22:34:34 +00:00
|
|
|
self._dummy_cycle(1, None, "", stickyauth = ".*")
|