2010-02-16 04:09:07 +00:00
|
|
|
import cStringIO
|
2015-04-13 23:58:10 +00:00
|
|
|
from netlib import odict
|
2011-08-03 10:38:23 +00:00
|
|
|
from libmproxy import filt, flow
|
2014-01-31 03:45:39 +00:00
|
|
|
from libmproxy.protocol import http
|
2014-02-04 04:02:17 +00:00
|
|
|
from libmproxy.protocol.primitives import Error
|
2014-01-31 03:45:39 +00:00
|
|
|
import tutils
|
2010-02-16 04:09:07 +00:00
|
|
|
|
2015-05-30 00:03:28 +00:00
|
|
|
|
2012-06-09 01:42:43 +00:00
|
|
|
class TestParsing:
|
2010-02-16 04:09:07 +00:00
|
|
|
def _dump(self, x):
|
|
|
|
c = cStringIO.StringIO()
|
|
|
|
x.dump(fp=c)
|
|
|
|
assert c.getvalue()
|
|
|
|
|
2012-02-10 02:22:26 +00:00
|
|
|
def test_parse_err(self):
|
2011-02-02 23:16:03 +00:00
|
|
|
assert filt.parse("~h [") is None
|
|
|
|
|
2010-02-16 04:09:07 +00:00
|
|
|
def test_simple(self):
|
|
|
|
assert not filt.parse("~b")
|
|
|
|
assert filt.parse("~q")
|
|
|
|
assert filt.parse("~c 10")
|
2011-12-28 22:32:29 +00:00
|
|
|
assert filt.parse("~m foobar")
|
2010-02-16 04:09:07 +00:00
|
|
|
assert filt.parse("~u foobar")
|
|
|
|
assert filt.parse("~q ~c 10")
|
|
|
|
p = filt.parse("~q ~c 10")
|
|
|
|
self._dump(p)
|
|
|
|
assert len(p.lst) == 2
|
|
|
|
|
|
|
|
def test_naked_url(self):
|
|
|
|
a = filt.parse("foobar ~h rex")
|
|
|
|
assert a.lst[0].expr == "foobar"
|
|
|
|
assert a.lst[1].expr == "rex"
|
|
|
|
self._dump(a)
|
|
|
|
|
|
|
|
def test_quoting(self):
|
|
|
|
a = filt.parse("~u 'foo ~u bar' ~u voing")
|
|
|
|
assert a.lst[0].expr == "foo ~u bar"
|
|
|
|
assert a.lst[1].expr == "voing"
|
|
|
|
self._dump(a)
|
|
|
|
|
|
|
|
a = filt.parse("~u foobar")
|
|
|
|
assert a.expr == "foobar"
|
|
|
|
|
|
|
|
a = filt.parse(r"~u 'foobar\"\''")
|
|
|
|
assert a.expr == "foobar\"'"
|
|
|
|
|
|
|
|
a = filt.parse(r'~u "foo \'bar"')
|
|
|
|
assert a.expr == "foo 'bar"
|
|
|
|
|
|
|
|
def test_nesting(self):
|
|
|
|
a = filt.parse("(~u foobar & ~h voing)")
|
|
|
|
assert a.lst[0].expr == "foobar"
|
|
|
|
self._dump(a)
|
|
|
|
|
|
|
|
def test_not(self):
|
|
|
|
a = filt.parse("!~h test")
|
|
|
|
assert a.itm.expr == "test"
|
|
|
|
a = filt.parse("!(~u test & ~h bar)")
|
|
|
|
assert a.itm.lst[0].expr == "test"
|
|
|
|
self._dump(a)
|
|
|
|
|
|
|
|
def test_binaryops(self):
|
|
|
|
a = filt.parse("~u foobar | ~h voing")
|
|
|
|
isinstance(a, filt.FOr)
|
|
|
|
self._dump(a)
|
|
|
|
|
|
|
|
a = filt.parse("~u foobar & ~h voing")
|
|
|
|
isinstance(a, filt.FAnd)
|
|
|
|
self._dump(a)
|
|
|
|
|
|
|
|
def test_wideops(self):
|
|
|
|
a = filt.parse("~hq 'header: qvalue'")
|
|
|
|
assert isinstance(a, filt.FHeadRequest)
|
|
|
|
self._dump(a)
|
|
|
|
|
|
|
|
|
2012-06-09 01:42:43 +00:00
|
|
|
class TestMatching:
|
2010-02-16 04:09:07 +00:00
|
|
|
def req(self):
|
2015-04-13 23:58:10 +00:00
|
|
|
headers = odict.ODictCaseless()
|
2010-02-16 04:09:07 +00:00
|
|
|
headers["header"] = ["qvalue"]
|
2014-01-31 03:45:39 +00:00
|
|
|
req = http.HTTPRequest(
|
|
|
|
"absolute",
|
|
|
|
"GET",
|
|
|
|
"http",
|
|
|
|
"host",
|
|
|
|
80,
|
|
|
|
"/path",
|
|
|
|
(1, 1),
|
|
|
|
headers,
|
|
|
|
"content_request",
|
|
|
|
None,
|
|
|
|
None
|
2010-02-16 04:09:07 +00:00
|
|
|
)
|
2014-01-31 03:45:39 +00:00
|
|
|
f = http.HTTPFlow(tutils.tclient_conn(), None)
|
|
|
|
f.request = req
|
|
|
|
return f
|
2010-02-16 04:09:07 +00:00
|
|
|
|
|
|
|
def resp(self):
|
2012-02-23 04:03:58 +00:00
|
|
|
f = self.req()
|
|
|
|
|
2015-04-13 23:58:10 +00:00
|
|
|
headers = odict.ODictCaseless()
|
2010-02-16 04:09:07 +00:00
|
|
|
headers["header_response"] = ["svalue"]
|
2015-05-30 00:03:28 +00:00
|
|
|
f.response = http.HTTPResponse(
|
|
|
|
(1,
|
|
|
|
1),
|
|
|
|
200,
|
|
|
|
"OK",
|
|
|
|
headers,
|
|
|
|
"content_response",
|
|
|
|
None,
|
|
|
|
None)
|
2014-01-31 03:45:39 +00:00
|
|
|
|
2012-02-23 04:03:58 +00:00
|
|
|
return f
|
2010-02-16 04:09:07 +00:00
|
|
|
|
2012-02-10 02:22:26 +00:00
|
|
|
def err(self):
|
2012-02-23 04:03:58 +00:00
|
|
|
f = self.req()
|
2014-02-04 04:02:17 +00:00
|
|
|
f.error = Error("msg")
|
2012-02-23 04:03:58 +00:00
|
|
|
return f
|
2012-02-10 02:22:26 +00:00
|
|
|
|
2010-02-16 04:09:07 +00:00
|
|
|
def q(self, q, o):
|
|
|
|
return filt.parse(q)(o)
|
|
|
|
|
2012-07-14 04:55:21 +00:00
|
|
|
def test_asset(self):
|
|
|
|
s = self.resp()
|
|
|
|
assert not self.q("~a", s)
|
|
|
|
s.response.headers["content-type"] = ["text/javascript"]
|
|
|
|
assert self.q("~a", s)
|
|
|
|
|
2010-02-16 04:09:07 +00:00
|
|
|
def test_fcontenttype(self):
|
|
|
|
q = self.req()
|
|
|
|
s = self.resp()
|
|
|
|
assert not self.q("~t content", q)
|
|
|
|
assert not self.q("~t content", s)
|
|
|
|
|
2012-02-23 04:03:58 +00:00
|
|
|
q.request.headers["content-type"] = ["text/json"]
|
2010-02-16 04:09:07 +00:00
|
|
|
assert self.q("~t json", q)
|
|
|
|
assert self.q("~tq json", q)
|
|
|
|
assert not self.q("~ts json", q)
|
|
|
|
|
2012-02-23 04:03:58 +00:00
|
|
|
s.response.headers["content-type"] = ["text/json"]
|
2010-02-16 04:09:07 +00:00
|
|
|
assert self.q("~t json", s)
|
|
|
|
|
2012-02-23 04:03:58 +00:00
|
|
|
del s.response.headers["content-type"]
|
2010-02-16 04:09:07 +00:00
|
|
|
s.request.headers["content-type"] = ["text/json"]
|
|
|
|
assert self.q("~t json", s)
|
|
|
|
assert self.q("~tq json", s)
|
|
|
|
assert not self.q("~ts json", s)
|
|
|
|
|
|
|
|
def test_freq_fresp(self):
|
|
|
|
q = self.req()
|
|
|
|
s = self.resp()
|
|
|
|
|
|
|
|
assert self.q("~q", q)
|
2012-02-23 04:06:09 +00:00
|
|
|
assert not self.q("~q", s)
|
2010-02-16 04:09:07 +00:00
|
|
|
|
|
|
|
assert not self.q("~s", q)
|
|
|
|
assert self.q("~s", s)
|
|
|
|
|
2012-02-10 02:22:26 +00:00
|
|
|
def test_ferr(self):
|
|
|
|
e = self.err()
|
|
|
|
assert self.q("~e", e)
|
|
|
|
|
2010-02-16 04:09:07 +00:00
|
|
|
def test_head(self):
|
|
|
|
q = self.req()
|
|
|
|
s = self.resp()
|
|
|
|
assert not self.q("~h nonexistent", q)
|
|
|
|
assert self.q("~h qvalue", q)
|
|
|
|
assert self.q("~h header", q)
|
|
|
|
assert self.q("~h 'header: qvalue'", q)
|
|
|
|
|
|
|
|
assert self.q("~h 'header: qvalue'", s)
|
|
|
|
assert self.q("~h 'header_response: svalue'", s)
|
|
|
|
|
|
|
|
assert self.q("~hq 'header: qvalue'", s)
|
|
|
|
assert not self.q("~hq 'header_response: svalue'", s)
|
|
|
|
|
|
|
|
assert self.q("~hq 'header: qvalue'", q)
|
|
|
|
assert not self.q("~hq 'header_request: svalue'", q)
|
|
|
|
|
|
|
|
assert not self.q("~hs 'header: qvalue'", s)
|
|
|
|
assert self.q("~hs 'header_response: svalue'", s)
|
|
|
|
assert not self.q("~hs 'header: qvalue'", q)
|
|
|
|
|
2014-08-03 00:34:29 +00:00
|
|
|
def match_body(self, q, s):
|
2010-02-16 04:09:07 +00:00
|
|
|
assert not self.q("~b nonexistent", q)
|
|
|
|
assert self.q("~b content", q)
|
|
|
|
assert self.q("~b response", s)
|
|
|
|
assert self.q("~b content_request", s)
|
|
|
|
|
|
|
|
assert self.q("~bq content", q)
|
|
|
|
assert self.q("~bq content", s)
|
|
|
|
assert not self.q("~bq response", q)
|
|
|
|
assert not self.q("~bq response", s)
|
|
|
|
|
|
|
|
assert not self.q("~bs content", q)
|
|
|
|
assert self.q("~bs content", s)
|
|
|
|
assert not self.q("~bs nomatch", s)
|
|
|
|
assert not self.q("~bs response", q)
|
|
|
|
assert self.q("~bs response", s)
|
|
|
|
|
2014-08-03 00:34:29 +00:00
|
|
|
def test_body(self):
|
|
|
|
q = self.req()
|
|
|
|
s = self.resp()
|
|
|
|
self.match_body(q, s)
|
|
|
|
|
|
|
|
q.request.encode("gzip")
|
|
|
|
s.request.encode("gzip")
|
|
|
|
s.response.encode("gzip")
|
|
|
|
self.match_body(q, s)
|
|
|
|
|
2011-12-28 22:32:29 +00:00
|
|
|
def test_method(self):
|
|
|
|
q = self.req()
|
|
|
|
s = self.resp()
|
|
|
|
assert self.q("~m get", q)
|
|
|
|
assert not self.q("~m post", q)
|
2012-02-23 04:03:58 +00:00
|
|
|
|
|
|
|
q.request.method = "oink"
|
2012-02-10 02:04:20 +00:00
|
|
|
assert not self.q("~m get", q)
|
2011-12-28 22:32:29 +00:00
|
|
|
|
2012-07-06 10:21:44 +00:00
|
|
|
def test_domain(self):
|
|
|
|
q = self.req()
|
|
|
|
s = self.resp()
|
|
|
|
assert self.q("~d host", q)
|
|
|
|
assert not self.q("~d none", q)
|
|
|
|
|
2010-02-16 04:09:07 +00:00
|
|
|
def test_url(self):
|
|
|
|
q = self.req()
|
|
|
|
s = self.resp()
|
|
|
|
assert self.q("~u host", q)
|
|
|
|
assert self.q("~u host/path", q)
|
|
|
|
assert not self.q("~u moo/path", q)
|
|
|
|
|
|
|
|
assert self.q("~u host", s)
|
|
|
|
assert self.q("~u host/path", s)
|
|
|
|
assert not self.q("~u moo/path", s)
|
|
|
|
|
|
|
|
def test_code(self):
|
|
|
|
q = self.req()
|
|
|
|
s = self.resp()
|
|
|
|
assert not self.q("~c 200", q)
|
|
|
|
assert self.q("~c 200", s)
|
|
|
|
assert not self.q("~c 201", s)
|
|
|
|
|
2015-07-13 21:07:39 +00:00
|
|
|
def test_src(self):
|
|
|
|
q = self.req()
|
|
|
|
assert self.q("~src address", q)
|
|
|
|
assert not self.q("~src foobar", q)
|
|
|
|
assert self.q("~src :22", q)
|
|
|
|
assert not self.q("~src :99", q)
|
|
|
|
assert self.q("~src address:22", q)
|
|
|
|
|
|
|
|
def test_dst(self):
|
|
|
|
q = self.req()
|
|
|
|
q.server_conn = tutils.tserver_conn()
|
|
|
|
assert self.q("~dst address", q)
|
|
|
|
assert not self.q("~dst foobar", q)
|
|
|
|
assert self.q("~dst :22", q)
|
|
|
|
assert not self.q("~dst :99", q)
|
|
|
|
assert self.q("~dst address:22", q)
|
|
|
|
|
2010-02-16 04:09:07 +00:00
|
|
|
def test_and(self):
|
|
|
|
s = self.resp()
|
|
|
|
assert self.q("~c 200 & ~h head", s)
|
2012-02-23 04:03:58 +00:00
|
|
|
assert self.q("~c 200 & ~h head", s)
|
2010-02-16 04:09:07 +00:00
|
|
|
assert not self.q("~c 200 & ~h nohead", s)
|
|
|
|
assert self.q("(~c 200 & ~h head) & ~b content", s)
|
|
|
|
assert not self.q("(~c 200 & ~h head) & ~b nonexistent", s)
|
|
|
|
assert not self.q("(~c 200 & ~h nohead) & ~b content", s)
|
|
|
|
|
|
|
|
def test_or(self):
|
|
|
|
s = self.resp()
|
|
|
|
assert self.q("~c 200 | ~h nohead", s)
|
|
|
|
assert self.q("~c 201 | ~h head", s)
|
|
|
|
assert not self.q("~c 201 | ~h nohead", s)
|
2012-02-23 04:06:09 +00:00
|
|
|
assert self.q("(~c 201 | ~h nohead) | ~s", s)
|
2010-02-16 04:09:07 +00:00
|
|
|
|
|
|
|
def test_not(self):
|
|
|
|
s = self.resp()
|
|
|
|
assert not self.q("! ~c 200", s)
|
|
|
|
assert self.q("! ~c 201", s)
|
|
|
|
assert self.q("!~c 201 !~c 202", s)
|
|
|
|
assert not self.q("!~c 201 !~c 200", s)
|