mirror of
https://github.com/Grasscutters/mitmproxy.git
synced 2024-11-30 03:14:22 +00:00
Refactor to extract ready_actions and write_values.
This commit is contained in:
parent
05f5e772c3
commit
d4ad3f0b2c
@ -33,7 +33,7 @@ class PathodHandler(tcp.BaseHandler):
|
|||||||
if not crafted and path.startswith(self.server.prefix):
|
if not crafted and path.startswith(self.server.prefix):
|
||||||
spec = urllib.unquote(path)[len(self.server.prefix):]
|
spec = urllib.unquote(path)[len(self.server.prefix):]
|
||||||
try:
|
try:
|
||||||
crafted = rparse.parse(self.server.request_settings, spec)
|
crafted = rparse.parse_response(self.server.request_settings, spec)
|
||||||
except rparse.ParseException, v:
|
except rparse.ParseException, v:
|
||||||
crafted = rparse.InternalResponse(
|
crafted = rparse.InternalResponse(
|
||||||
800,
|
800,
|
||||||
@ -95,7 +95,7 @@ class Pathod(tcp.TCPServer):
|
|||||||
except re.error:
|
except re.error:
|
||||||
raise PathodError("Invalid regex in anchor: %s"%i[0])
|
raise PathodError("Invalid regex in anchor: %s"%i[0])
|
||||||
try:
|
try:
|
||||||
aresp = rparse.parse(self.request_settings, i[1])
|
aresp = rparse.parse_response(self.request_settings, i[1])
|
||||||
except rparse.ParseException, v:
|
except rparse.ParseException, v:
|
||||||
raise PathodError("Invalid page spec in anchor: '%s', %s"%(i[1], str(v)))
|
raise PathodError("Invalid page spec in anchor: '%s', %s"%(i[1], str(v)))
|
||||||
self.anchors.append((arex, aresp))
|
self.anchors.append((arex, aresp))
|
||||||
|
@ -2,6 +2,8 @@ import operator, string, random, mmap, os, time
|
|||||||
import contrib.pyparsing as pp
|
import contrib.pyparsing as pp
|
||||||
from netlib import http_status
|
from netlib import http_status
|
||||||
|
|
||||||
|
BLOCKSIZE = 1024
|
||||||
|
|
||||||
class ParseException(Exception):
|
class ParseException(Exception):
|
||||||
def __init__(self, msg, s, col):
|
def __init__(self, msg, s, col):
|
||||||
Exception.__init__(self)
|
Exception.__init__(self)
|
||||||
@ -19,6 +21,52 @@ class ParseException(Exception):
|
|||||||
class ServerError(Exception): pass
|
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(
|
DATATYPES = dict(
|
||||||
ascii_letters = string.ascii_letters,
|
ascii_letters = string.ascii_letters,
|
||||||
ascii_lowercase = string.ascii_lowercase,
|
ascii_lowercase = string.ascii_lowercase,
|
||||||
@ -328,7 +376,6 @@ class Code:
|
|||||||
return e.setParseAction(lambda x: klass(*x))
|
return e.setParseAction(lambda x: klass(*x))
|
||||||
|
|
||||||
|
|
||||||
BLOCKSIZE = 1024
|
|
||||||
class Response:
|
class Response:
|
||||||
comps = (
|
comps = (
|
||||||
Body,
|
Body,
|
||||||
@ -375,46 +422,6 @@ class Response:
|
|||||||
l += len(self.body)
|
l += len(self.body)
|
||||||
return l
|
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):
|
def serve(self, fp):
|
||||||
started = time.time()
|
started = time.time()
|
||||||
if self.body and not self.get_header("Content-Length"):
|
if self.body and not self.get_header("Content-Length"):
|
||||||
@ -443,9 +450,9 @@ class Response:
|
|||||||
if self.body:
|
if self.body:
|
||||||
vals.append(self.body)
|
vals.append(self.body)
|
||||||
vals.reverse()
|
vals.reverse()
|
||||||
actions = self.ready_actions(self.length(), self.actions)
|
actions = ready_actions(self.length(), self.actions)
|
||||||
actions.reverse()
|
actions.reverse()
|
||||||
disconnect = self.write_values(fp, vals, actions[:])
|
disconnect = write_values(fp, vals, actions[:])
|
||||||
duration = time.time() - started
|
duration = time.time() - started
|
||||||
return dict(
|
return dict(
|
||||||
disconnect = disconnect,
|
disconnect = disconnect,
|
||||||
@ -498,7 +505,7 @@ class InternalResponse(Response):
|
|||||||
return d
|
return d
|
||||||
|
|
||||||
|
|
||||||
def parse(settings, s):
|
def parse_response(settings, s):
|
||||||
try:
|
try:
|
||||||
return CraftedResponse(settings, s, Response.expr().parseString(s, parseAll=True))
|
return CraftedResponse(settings, s, Response.expr().parseString(s, parseAll=True))
|
||||||
except pp.ParseException, v:
|
except pp.ParseException, v:
|
||||||
|
@ -137,9 +137,9 @@ class TestMisc:
|
|||||||
|
|
||||||
|
|
||||||
class TestDisconnects:
|
class TestDisconnects:
|
||||||
def test_parse(self):
|
def test_parse_response(self):
|
||||||
assert (0, "disconnect") in rparse.parse({}, "400:d0").actions
|
assert (0, "disconnect") in rparse.parse_response({}, "400:d0").actions
|
||||||
assert ("r", "disconnect") in rparse.parse({}, "400:dr").actions
|
assert ("r", "disconnect") in rparse.parse_response({}, "400:dr").actions
|
||||||
|
|
||||||
def test_at(self):
|
def test_at(self):
|
||||||
e = rparse.DisconnectAt.expr()
|
e = rparse.DisconnectAt.expr()
|
||||||
@ -156,13 +156,13 @@ class TestDisconnects:
|
|||||||
|
|
||||||
|
|
||||||
class TestShortcuts:
|
class TestShortcuts:
|
||||||
def test_parse(self):
|
def test_parse_response(self):
|
||||||
assert rparse.parse({}, "400:c'foo'").headers[0][0][:] == "Content-Type"
|
assert rparse.parse_response({}, "400:c'foo'").headers[0][0][:] == "Content-Type"
|
||||||
assert rparse.parse({}, "400:l'foo'").headers[0][0][:] == "Location"
|
assert rparse.parse_response({}, "400:l'foo'").headers[0][0][:] == "Location"
|
||||||
|
|
||||||
|
|
||||||
class TestPauses:
|
class TestPauses:
|
||||||
def test_parse(self):
|
def test_parse_response(self):
|
||||||
e = rparse.PauseAt.expr()
|
e = rparse.PauseAt.expr()
|
||||||
v = e.parseString("p10,10")[0]
|
v = e.parseString("p10,10")[0]
|
||||||
assert v.seconds == 10
|
assert v.seconds == 10
|
||||||
@ -178,109 +178,105 @@ class TestPauses:
|
|||||||
assert v.offset == "a"
|
assert v.offset == "a"
|
||||||
|
|
||||||
def test_request(self):
|
def test_request(self):
|
||||||
r = rparse.parse({}, '400:p10,10')
|
r = rparse.parse_response({}, '400:p10,10')
|
||||||
assert r.actions[0] == (10, "pause", 10)
|
assert r.actions[0] == (10, "pause", 10)
|
||||||
|
|
||||||
|
|
||||||
class TestParse:
|
class TestParse:
|
||||||
def test_parse_err(self):
|
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:
|
try:
|
||||||
rparse.parse({}, "400'msg':b:")
|
rparse.parse_response({}, "400'msg':b:")
|
||||||
except rparse.ParseException, v:
|
except rparse.ParseException, v:
|
||||||
assert v.marked()
|
assert v.marked()
|
||||||
assert str(v)
|
assert str(v)
|
||||||
|
|
||||||
def test_parse_header(self):
|
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"
|
assert r.get_header("foo") == "bar"
|
||||||
|
|
||||||
def test_parse_pause_before(self):
|
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
|
assert (0, "pause", 10) in r.actions
|
||||||
|
|
||||||
def test_parse_pause_after(self):
|
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
|
assert ("a", "pause", 10) in r.actions
|
||||||
|
|
||||||
def test_parse_pause_random(self):
|
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
|
assert ("r", "pause", 10) in r.actions
|
||||||
|
|
||||||
def test_parse_stress(self):
|
def test_parse_stress(self):
|
||||||
r = rparse.parse({}, "400:b@100g")
|
r = rparse.parse_response({}, "400:b@100g")
|
||||||
assert r.length()
|
assert r.length()
|
||||||
|
|
||||||
|
|
||||||
class TestResponse:
|
class TestWriteValues:
|
||||||
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)
|
|
||||||
|
|
||||||
def test_write_values_disconnects(self):
|
def test_write_values_disconnects(self):
|
||||||
r = self.dummy_response()
|
|
||||||
s = cStringIO.StringIO()
|
s = cStringIO.StringIO()
|
||||||
tst = "foo"*100
|
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()
|
assert not s.getvalue()
|
||||||
|
|
||||||
def test_write_values(self):
|
def test_write_values(self):
|
||||||
tst = "foo"*1025
|
tst = "foo"*1025
|
||||||
r = rparse.parse({}, "400'msg'")
|
|
||||||
|
|
||||||
s = cStringIO.StringIO()
|
s = cStringIO.StringIO()
|
||||||
r.write_values(s, [tst], [])
|
rparse.write_values(s, [tst], [])
|
||||||
assert s.getvalue() == tst
|
assert s.getvalue() == tst
|
||||||
|
|
||||||
def test_write_values_pauses(self):
|
def test_write_values_pauses(self):
|
||||||
tst = "".join(str(i) for i in range(10))
|
tst = "".join(str(i) for i in range(10))
|
||||||
r = rparse.parse({}, "400'msg'")
|
|
||||||
|
|
||||||
for i in range(2, 10):
|
for i in range(2, 10):
|
||||||
s = cStringIO.StringIO()
|
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
|
assert s.getvalue() == tst
|
||||||
|
|
||||||
for i in range(2, 10):
|
for i in range(2, 10):
|
||||||
s = cStringIO.StringIO()
|
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
|
assert s.getvalue() == tst
|
||||||
|
|
||||||
tst = ["".join(str(i) for i in range(10))]*5
|
tst = ["".join(str(i) for i in range(10))]*5
|
||||||
for i in range(2, 10):
|
for i in range(2, 10):
|
||||||
s = cStringIO.StringIO()
|
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)
|
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):
|
def test_render(self):
|
||||||
s = cStringIO.StringIO()
|
s = cStringIO.StringIO()
|
||||||
r = rparse.parse({}, "400'msg'")
|
r = rparse.parse_response({}, "400'msg'")
|
||||||
assert r.serve(s)
|
assert r.serve(s)
|
||||||
|
|
||||||
def test_length(self):
|
def test_length(self):
|
||||||
@ -288,6 +284,6 @@ class TestResponse:
|
|||||||
s = cStringIO.StringIO()
|
s = cStringIO.StringIO()
|
||||||
x.serve(s)
|
x.serve(s)
|
||||||
assert x.length() == len(s.getvalue())
|
assert x.length() == len(s.getvalue())
|
||||||
testlen(rparse.parse({}, "400'msg'"))
|
testlen(rparse.parse_response({}, "400'msg'"))
|
||||||
testlen(rparse.parse({}, "400'msg':h'foo'='bar'"))
|
testlen(rparse.parse_response({}, "400'msg':h'foo'='bar'"))
|
||||||
testlen(rparse.parse({}, "400'msg':h'foo'='bar':b@100b"))
|
testlen(rparse.parse_response({}, "400'msg':h'foo'='bar':b@100b"))
|
||||||
|
Loading…
Reference in New Issue
Block a user