aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAldo Cortesi <aldo@nullcube.com>2012-06-24 17:01:04 +1200
committerAldo Cortesi <aldo@nullcube.com>2012-06-24 17:01:04 +1200
commitd4ad3f0b2cc5ae878108e13e86679fac2abaedb2 (patch)
tree5341869d10a041fb785f576418a5bc032341730b
parent05f5e772c3f59c9be40132eb7afd4f049ced140a (diff)
downloadmitmproxy-d4ad3f0b2cc5ae878108e13e86679fac2abaedb2.tar.gz
mitmproxy-d4ad3f0b2cc5ae878108e13e86679fac2abaedb2.tar.bz2
mitmproxy-d4ad3f0b2cc5ae878108e13e86679fac2abaedb2.zip
Refactor to extract ready_actions and write_values.
-rw-r--r--libpathod/pathod.py4
-rw-r--r--libpathod/rparse.py95
-rw-r--r--test/test_rparse.py116
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"))