diff options
author | Aldo Cortesi <aldo@nullcube.com> | 2012-06-24 17:01:04 +1200 |
---|---|---|
committer | Aldo Cortesi <aldo@nullcube.com> | 2012-06-24 17:01:04 +1200 |
commit | d4ad3f0b2cc5ae878108e13e86679fac2abaedb2 (patch) | |
tree | 5341869d10a041fb785f576418a5bc032341730b | |
parent | 05f5e772c3f59c9be40132eb7afd4f049ced140a (diff) | |
download | mitmproxy-d4ad3f0b2cc5ae878108e13e86679fac2abaedb2.tar.gz mitmproxy-d4ad3f0b2cc5ae878108e13e86679fac2abaedb2.tar.bz2 mitmproxy-d4ad3f0b2cc5ae878108e13e86679fac2abaedb2.zip |
Refactor to extract ready_actions and write_values.
-rw-r--r-- | libpathod/pathod.py | 4 | ||||
-rw-r--r-- | libpathod/rparse.py | 95 | ||||
-rw-r--r-- | test/test_rparse.py | 116 |
3 files changed, 109 insertions, 106 deletions
diff --git a/libpathod/pathod.py b/libpathod/pathod.py index ba537768..c84be420 100644 --- a/libpathod/pathod.py +++ b/libpathod/pathod.py @@ -33,7 +33,7 @@ class PathodHandler(tcp.BaseHandler): if not crafted and path.startswith(self.server.prefix): spec = urllib.unquote(path)[len(self.server.prefix):] try: - crafted = rparse.parse(self.server.request_settings, spec) + crafted = rparse.parse_response(self.server.request_settings, spec) except rparse.ParseException, v: crafted = rparse.InternalResponse( 800, @@ -95,7 +95,7 @@ class Pathod(tcp.TCPServer): except re.error: raise PathodError("Invalid regex in anchor: %s"%i[0]) try: - aresp = rparse.parse(self.request_settings, i[1]) + aresp = rparse.parse_response(self.request_settings, i[1]) except rparse.ParseException, v: raise PathodError("Invalid page spec in anchor: '%s', %s"%(i[1], str(v))) self.anchors.append((arex, aresp)) diff --git a/libpathod/rparse.py b/libpathod/rparse.py index 8a407388..91ba6356 100644 --- a/libpathod/rparse.py +++ b/libpathod/rparse.py @@ -2,6 +2,8 @@ import operator, string, random, mmap, os, time import contrib.pyparsing as pp from netlib import http_status +BLOCKSIZE = 1024 + class ParseException(Exception): def __init__(self, msg, s, col): Exception.__init__(self) @@ -19,6 +21,52 @@ class ParseException(Exception): class ServerError(Exception): pass +def ready_actions(l, lst): + ret = [] + for i in lst: + itms = list(i) + if i[0] == "r": + itms[0] = random.randrange(l) + if i[0] == "a": + itms[0] = l+1 + ret.append(tuple(itms)) + ret.sort() + return ret + + +def write_values(fp, vals, actions, sofar=0, skip=0, blocksize=BLOCKSIZE): + """ + vals: A list of values, which may be strings or Value objects. + actions: A list of (offset, action, arg) tuples. Action may be "pause" or "disconnect". + + Return True if connection should disconnect. + """ + while vals: + part = vals.pop() + for i in range(skip, len(part), blocksize): + d = part[i:i+blocksize] + if actions and actions[-1][0] < (sofar + len(d)): + p = actions.pop() + offset = p[0]-sofar + vals.append(part) + if p[1] == "pause": + fp.write(d[:offset]) + time.sleep(p[2]) + return write_values( + fp, vals, actions, + sofar=sofar+offset, + skip=i+offset, + blocksize=blocksize + ) + elif p[1] == "disconnect": + fp.write(d[:offset]) + return True + fp.write(d) + sofar += len(d) + skip = 0 + + + DATATYPES = dict( ascii_letters = string.ascii_letters, ascii_lowercase = string.ascii_lowercase, @@ -328,7 +376,6 @@ class Code: return e.setParseAction(lambda x: klass(*x)) -BLOCKSIZE = 1024 class Response: comps = ( Body, @@ -375,46 +422,6 @@ class Response: l += len(self.body) return l - def ready_actions(self, l, lst): - ret = [] - for i in lst: - itms = list(i) - if i[0] == "r": - itms[0] = random.randrange(l) - if i[0] == "a": - itms[0] = l+1 - ret.append(tuple(itms)) - ret.sort() - return ret - - def write_values(self, fp, vals, actions, sofar=0, skip=0, blocksize=BLOCKSIZE): - """ - Return True if connection should disconnect. - """ - while vals: - part = vals.pop() - for i in range(skip, len(part), blocksize): - d = part[i:i+blocksize] - if actions and actions[-1][0] < (sofar + len(d)): - p = actions.pop() - offset = p[0]-sofar - vals.append(part) - if p[1] == "pause": - fp.write(d[:offset]) - time.sleep(p[2]) - return self.write_values( - fp, vals, actions, - sofar=sofar+offset, - skip=i+offset, - blocksize=blocksize - ) - elif p[1] == "disconnect": - fp.write(d[:offset]) - return True - fp.write(d) - sofar += len(d) - skip = 0 - def serve(self, fp): started = time.time() if self.body and not self.get_header("Content-Length"): @@ -443,9 +450,9 @@ class Response: if self.body: vals.append(self.body) vals.reverse() - actions = self.ready_actions(self.length(), self.actions) + actions = ready_actions(self.length(), self.actions) actions.reverse() - disconnect = self.write_values(fp, vals, actions[:]) + disconnect = write_values(fp, vals, actions[:]) duration = time.time() - started return dict( disconnect = disconnect, @@ -498,7 +505,7 @@ class InternalResponse(Response): return d -def parse(settings, s): +def parse_response(settings, s): try: return CraftedResponse(settings, s, Response.expr().parseString(s, parseAll=True)) except pp.ParseException, v: diff --git a/test/test_rparse.py b/test/test_rparse.py index 0813f22e..727a89f6 100644 --- a/test/test_rparse.py +++ b/test/test_rparse.py @@ -137,9 +137,9 @@ class TestMisc: class TestDisconnects: - def test_parse(self): - assert (0, "disconnect") in rparse.parse({}, "400:d0").actions - assert ("r", "disconnect") in rparse.parse({}, "400:dr").actions + def test_parse_response(self): + assert (0, "disconnect") in rparse.parse_response({}, "400:d0").actions + assert ("r", "disconnect") in rparse.parse_response({}, "400:dr").actions def test_at(self): e = rparse.DisconnectAt.expr() @@ -156,13 +156,13 @@ class TestDisconnects: class TestShortcuts: - def test_parse(self): - assert rparse.parse({}, "400:c'foo'").headers[0][0][:] == "Content-Type" - assert rparse.parse({}, "400:l'foo'").headers[0][0][:] == "Location" + def test_parse_response(self): + assert rparse.parse_response({}, "400:c'foo'").headers[0][0][:] == "Content-Type" + assert rparse.parse_response({}, "400:l'foo'").headers[0][0][:] == "Location" class TestPauses: - def test_parse(self): + def test_parse_response(self): e = rparse.PauseAt.expr() v = e.parseString("p10,10")[0] assert v.seconds == 10 @@ -178,109 +178,105 @@ class TestPauses: assert v.offset == "a" def test_request(self): - r = rparse.parse({}, '400:p10,10') + r = rparse.parse_response({}, '400:p10,10') assert r.actions[0] == (10, "pause", 10) class TestParse: def test_parse_err(self): - tutils.raises(rparse.ParseException, rparse.parse, {}, "400:msg,b:") + tutils.raises(rparse.ParseException, rparse.parse_response, {}, "400:msg,b:") try: - rparse.parse({}, "400'msg':b:") + rparse.parse_response({}, "400'msg':b:") except rparse.ParseException, v: assert v.marked() assert str(v) def test_parse_header(self): - r = rparse.parse({}, '400:h"foo"="bar"') + r = rparse.parse_response({}, '400:h"foo"="bar"') assert r.get_header("foo") == "bar" def test_parse_pause_before(self): - r = rparse.parse({}, "400:p10,0") + r = rparse.parse_response({}, "400:p10,0") assert (0, "pause", 10) in r.actions def test_parse_pause_after(self): - r = rparse.parse({}, "400:p10,a") + r = rparse.parse_response({}, "400:p10,a") assert ("a", "pause", 10) in r.actions def test_parse_pause_random(self): - r = rparse.parse({}, "400:p10,r") + r = rparse.parse_response({}, "400:p10,r") assert ("r", "pause", 10) in r.actions def test_parse_stress(self): - r = rparse.parse({}, "400:b@100g") + r = rparse.parse_response({}, "400:b@100g") assert r.length() -class TestResponse: - def dummy_response(self): - return rparse.parse({}, "400'msg'") - - def test_response(self): - r = rparse.parse({}, "400'msg'") - assert r.code == 400 - assert r.msg == "msg" - - r = rparse.parse({}, "400'msg':b@100b") - assert r.msg == "msg" - assert r.body[:] - assert str(r) - - def test_ready_actions(self): - r = rparse.parse({}, "400'msg'") - - x = [(0, 5)] - assert r.ready_actions(100, x) == x - - x = [("r", 5)] - ret = r.ready_actions(100, x) - assert 0 <= ret[0][0] < 100 - - x = [("a", "pause", 5)] - ret = r.ready_actions(100, x) - assert ret[0][0] > 100 - - x = [(1, 5), (0, 5)] - assert r.ready_actions(100, x) == sorted(x) - +class TestWriteValues: def test_write_values_disconnects(self): - r = self.dummy_response() s = cStringIO.StringIO() tst = "foo"*100 - r.write_values(s, [tst], [(0, "disconnect")], blocksize=5) + rparse.write_values(s, [tst], [(0, "disconnect")], blocksize=5) assert not s.getvalue() def test_write_values(self): tst = "foo"*1025 - r = rparse.parse({}, "400'msg'") - s = cStringIO.StringIO() - r.write_values(s, [tst], []) + rparse.write_values(s, [tst], []) assert s.getvalue() == tst def test_write_values_pauses(self): tst = "".join(str(i) for i in range(10)) - r = rparse.parse({}, "400'msg'") - for i in range(2, 10): s = cStringIO.StringIO() - r.write_values(s, [tst], [(2, "pause", 0), (1, "pause", 0)], blocksize=i) + rparse.write_values(s, [tst], [(2, "pause", 0), (1, "pause", 0)], blocksize=i) assert s.getvalue() == tst for i in range(2, 10): s = cStringIO.StringIO() - r.write_values(s, [tst], [(1, "pause", 0)], blocksize=i) + rparse.write_values(s, [tst], [(1, "pause", 0)], blocksize=i) assert s.getvalue() == tst tst = ["".join(str(i) for i in range(10))]*5 for i in range(2, 10): s = cStringIO.StringIO() - r.write_values(s, tst[:], [(1, "pause", 0)], blocksize=i) + rparse.write_values(s, tst[:], [(1, "pause", 0)], blocksize=i) assert s.getvalue() == "".join(tst) + +def test_ready_actions(): + x = [(0, 5)] + assert rparse.ready_actions(100, x) == x + + x = [("r", 5)] + ret = rparse.ready_actions(100, x) + assert 0 <= ret[0][0] < 100 + + x = [("a", "pause", 5)] + ret = rparse.ready_actions(100, x) + assert ret[0][0] > 100 + + x = [(1, 5), (0, 5)] + assert rparse.ready_actions(100, x) == sorted(x) + + +class TestResponse: + def dummy_response(self): + return rparse.parse_response({}, "400'msg'") + + def test_response(self): + r = rparse.parse_response({}, "400'msg'") + assert r.code == 400 + assert r.msg == "msg" + + r = rparse.parse_response({}, "400'msg':b@100b") + assert r.msg == "msg" + assert r.body[:] + assert str(r) + def test_render(self): s = cStringIO.StringIO() - r = rparse.parse({}, "400'msg'") + r = rparse.parse_response({}, "400'msg'") assert r.serve(s) def test_length(self): @@ -288,6 +284,6 @@ class TestResponse: s = cStringIO.StringIO() x.serve(s) assert x.length() == len(s.getvalue()) - testlen(rparse.parse({}, "400'msg'")) - testlen(rparse.parse({}, "400'msg':h'foo'='bar'")) - testlen(rparse.parse({}, "400'msg':h'foo'='bar':b@100b")) + testlen(rparse.parse_response({}, "400'msg'")) + testlen(rparse.parse_response({}, "400'msg':h'foo'='bar'")) + testlen(rparse.parse_response({}, "400'msg':h'foo'='bar':b@100b")) |