mirror of
https://github.com/Grasscutters/mitmproxy.git
synced 2024-11-27 02:24:18 +00:00
Make specification language more terse, and more regular.
This commit is contained in:
parent
5fc2a63781
commit
a779aac9db
@ -15,6 +15,9 @@ class ParseException(Exception):
|
||||
def marked(self):
|
||||
return "%s\n%s"%(self.s, " "*(self.col-1) + "^")
|
||||
|
||||
def __str__(self):
|
||||
return self.msg
|
||||
|
||||
|
||||
class ServerError(Exception): pass
|
||||
|
||||
@ -41,16 +44,17 @@ v_integer = pp.Regex(r"[+-]?\d+")\
|
||||
.setName("integer")\
|
||||
.setParseAction(lambda toks: int(toks[0]))
|
||||
|
||||
v_string = pp.MatchFirst(
|
||||
|
||||
v_literal = pp.MatchFirst(
|
||||
[
|
||||
pp.QuotedString("\"", escChar="\\", unquoteResults=True),
|
||||
pp.QuotedString("'", escChar="\\", unquoteResults=True),
|
||||
]
|
||||
)
|
||||
|
||||
v_literal = pp.MatchFirst(
|
||||
v_naked_literal = pp.MatchFirst(
|
||||
[
|
||||
v_string,
|
||||
v_literal,
|
||||
pp.Word("".join(i for i in pp.printables if i not in ",:"))
|
||||
]
|
||||
)
|
||||
@ -121,6 +125,13 @@ class ValueLiteral:
|
||||
return self.val
|
||||
|
||||
|
||||
class ValueNakedLiteral(ValueLiteral):
|
||||
@classmethod
|
||||
def expr(klass):
|
||||
e = v_naked_literal.copy()
|
||||
return e.setParseAction(lambda x: klass(*x))
|
||||
|
||||
|
||||
class ValueGenerate:
|
||||
UNITS = dict(
|
||||
b = 1024**0,
|
||||
@ -163,7 +174,7 @@ class ValueFile:
|
||||
@classmethod
|
||||
def expr(klass):
|
||||
e = pp.Literal("<").suppress()
|
||||
e = e + v_literal
|
||||
e = e + v_naked_literal
|
||||
return e.setParseAction(lambda x: klass(*x))
|
||||
|
||||
def get_generator(self, settings):
|
||||
@ -197,7 +208,7 @@ class Body:
|
||||
|
||||
@classmethod
|
||||
def expr(klass):
|
||||
e = pp.Literal("b:").suppress()
|
||||
e = pp.Literal("b").suppress()
|
||||
e = e + Value
|
||||
return e.setParseAction(lambda x: klass(*x))
|
||||
|
||||
@ -208,7 +219,7 @@ class _Pause:
|
||||
|
||||
@classmethod
|
||||
def expr(klass):
|
||||
e = pp.Literal("p%s:"%klass.sub).suppress()
|
||||
e = pp.Literal("p%s"%klass.sub).suppress()
|
||||
e = e + pp.MatchFirst(
|
||||
[
|
||||
v_integer,
|
||||
@ -273,7 +284,7 @@ class Header:
|
||||
|
||||
@classmethod
|
||||
def expr(klass):
|
||||
e = pp.Literal("h:").suppress()
|
||||
e = pp.Literal("h").suppress()
|
||||
e += Value
|
||||
e += pp.Literal(":").suppress()
|
||||
e += Value
|
||||
@ -294,7 +305,7 @@ class Code:
|
||||
def expr(klass):
|
||||
e = v_integer
|
||||
e = e + pp.Optional(
|
||||
pp.Literal(":").suppress() + Value
|
||||
Value
|
||||
)
|
||||
return e.setParseAction(lambda x: klass(*x))
|
||||
|
||||
|
103
notes
103
notes
@ -1,92 +1,53 @@
|
||||
|
||||
Response:
|
||||
|
||||
code[msg],[comma-separated features]
|
||||
|
||||
|
||||
Features:
|
||||
|
||||
hVALUE:VALUE Set header
|
||||
bVALUE Set body
|
||||
db Disconnect before sending data
|
||||
dr Disconnect randomly
|
||||
pbTIME Pause before sending data for NUM seconds or forever
|
||||
paTIME Pause after sending all data for NUM seconds or forever
|
||||
prTIME Pause randomly for NUM seconds or forever
|
||||
|
||||
cVALUE Set Content-Type header
|
||||
lVALUE Set Location header
|
||||
|
||||
|
||||
Time Specifiers:
|
||||
|
||||
5 - 5 seconds
|
||||
5s - 5 seconds
|
||||
5m - 5 minutes
|
||||
5h - 5 hours
|
||||
|
||||
|
||||
Value Specifiers:
|
||||
|
||||
!500k - 500k of random data
|
||||
!500k:utf8 - 500k of utf8. Other specifiers: utf8,alphanum,alpha,printable
|
||||
"foo" - literal
|
||||
foo - literal
|
||||
<path - load from path under data directory
|
||||
<"path literal" - load from path under data directory
|
||||
|
||||
|
||||
Response:
|
||||
|
||||
code:[comma-separated features]
|
||||
|
||||
|
||||
Specifying a response:
|
||||
Code 200:
|
||||
code:msg
|
||||
200:VALUE
|
||||
|
||||
Headers:
|
||||
h:VALUE:VALUE
|
||||
|
||||
Body:
|
||||
b:VALUE
|
||||
|
||||
Pauses:
|
||||
pb:5
|
||||
pb:forever
|
||||
|
||||
Pause before sending data:
|
||||
|
||||
pb:5
|
||||
|
||||
Pause after sending data, before hanging up:
|
||||
|
||||
pa:5
|
||||
|
||||
Pause after sending a random amoutn of data:
|
||||
|
||||
pr:5
|
||||
|
||||
|
||||
Disconnect:
|
||||
|
||||
Before sending data:
|
||||
|
||||
db
|
||||
|
||||
Randomly:
|
||||
|
||||
dr
|
||||
|
||||
|
||||
Shortcuts:
|
||||
|
||||
Redirects:
|
||||
code:msg>destination
|
||||
code>destination
|
||||
|
||||
301:VALUE>VALUE
|
||||
301>http://foo.bar
|
||||
|
||||
|
||||
Content-type:
|
||||
|
||||
t:content-type
|
||||
<"path" - load from path under data directory
|
||||
|
||||
|
||||
Examples:
|
||||
200,b:500k
|
||||
|
||||
404,p:5s,b:1k:printable
|
||||
|
||||
200,t:text/json,p:5s,b:1k
|
||||
|
||||
200,b:1k,xr
|
||||
|
||||
200,b500k
|
||||
404,pb5,b1k:printable
|
||||
200,t"text/json",pr5,b1k
|
||||
200,b1k,xr
|
||||
|
||||
|
||||
Sequences:
|
||||
|
||||
200 * 2 | !forever
|
||||
|
||||
200 | 404 | 200,b:500g
|
||||
|
||||
|
||||
|
||||
Anchors:
|
||||
|
||||
Passed on command-line?
|
||||
|
@ -17,7 +17,7 @@ class DummyRequest(StringIO.StringIO):
|
||||
|
||||
class uMisc(libpry.AutoTree):
|
||||
def test_generators(self):
|
||||
v = rparse.Value.parseString("val")[0]
|
||||
v = rparse.Value.parseString("'val'")[0]
|
||||
g = v.get_generator({})
|
||||
assert g[:] == "val"
|
||||
|
||||
@ -94,26 +94,25 @@ class uMisc(libpry.AutoTree):
|
||||
assert v.datatype == "digits"
|
||||
|
||||
def test_value(self):
|
||||
assert rparse.Value.parseString("val")[0].val == "val"
|
||||
assert rparse.Value.parseString("'val'")[0].val == "val"
|
||||
assert rparse.Value.parseString('"val"')[0].val == "val"
|
||||
assert rparse.Value.parseString('"\'val\'"')[0].val == "'val'"
|
||||
|
||||
def test_body(self):
|
||||
e = rparse.Body.expr()
|
||||
v = e.parseString("b:foo")[0]
|
||||
v = e.parseString("b'foo'")[0]
|
||||
assert v.value.val == "foo"
|
||||
|
||||
v = e.parseString("b:!100")[0]
|
||||
v = e.parseString("b!100")[0]
|
||||
assert str(v.value) == "!100b:bytes"
|
||||
|
||||
v = e.parseString("b:!100g:digits", parseAll=True)[0]
|
||||
v = e.parseString("b!100g:digits", parseAll=True)[0]
|
||||
assert v.value.datatype == "digits"
|
||||
assert str(v.value) == "!100g:digits"
|
||||
|
||||
def test_header(self):
|
||||
e = rparse.Header.expr()
|
||||
v = e.parseString("h:foo:bar")[0]
|
||||
v = e.parseString("h'foo':'bar'")[0]
|
||||
assert v.key.val == "foo"
|
||||
assert v.value.val == "bar"
|
||||
|
||||
@ -122,17 +121,17 @@ class uMisc(libpry.AutoTree):
|
||||
v = e.parseString("200")[0]
|
||||
assert v.code == 200
|
||||
|
||||
v = e.parseString("404:msg")[0]
|
||||
v = e.parseString("404'msg'")[0]
|
||||
assert v.code == 404
|
||||
assert v.msg.val == "msg"
|
||||
|
||||
r = e.parseString("200:'foo'")[0]
|
||||
r = e.parseString("200'foo'")[0]
|
||||
assert r.msg.val == "foo"
|
||||
|
||||
r = e.parseString("200:'\"foo\"'")[0]
|
||||
r = e.parseString("200'\"foo\"'")[0]
|
||||
assert r.msg.val == "\"foo\""
|
||||
|
||||
r = e.parseString('200:"foo"')[0]
|
||||
r = e.parseString('200"foo"')[0]
|
||||
assert r.msg.val == "foo"
|
||||
|
||||
r = e.parseString('404')[0]
|
||||
@ -168,20 +167,20 @@ class uDisconnects(libpry.AutoTree):
|
||||
class uPauses(libpry.AutoTree):
|
||||
def test_before(self):
|
||||
e = rparse.PauseBefore.expr()
|
||||
v = e.parseString("pb:10")[0]
|
||||
v = e.parseString("pb10")[0]
|
||||
assert v.value == 10
|
||||
|
||||
v = e.parseString("pb:forever")[0]
|
||||
v = e.parseString("pbforever")[0]
|
||||
assert v.value == "forever"
|
||||
|
||||
def test_after(self):
|
||||
e = rparse.PauseAfter.expr()
|
||||
v = e.parseString("pa:10")[0]
|
||||
v = e.parseString("pa10")[0]
|
||||
assert v.value == 10
|
||||
|
||||
def test_random(self):
|
||||
e = rparse.PauseRandom.expr()
|
||||
v = e.parseString("pr:10")[0]
|
||||
v = e.parseString("pr10")[0]
|
||||
assert v.value == 10
|
||||
|
||||
|
||||
@ -191,41 +190,41 @@ class uparse(libpry.AutoTree):
|
||||
try:
|
||||
rparse.parse({}, "400:msg,b:")
|
||||
except rparse.ParseException, v:
|
||||
print v.marked()
|
||||
assert v.marked()
|
||||
|
||||
def test_parse_header(self):
|
||||
r = rparse.parse({}, "400,h:foo:bar")
|
||||
r = rparse.parse({}, '400,h"foo":"bar"')
|
||||
assert r.get_header("foo") == "bar"
|
||||
|
||||
def test_parse_pause_before(self):
|
||||
r = rparse.parse({}, "400,pb:10")
|
||||
r = rparse.parse({}, "400,pb10")
|
||||
assert (0, 10) in r.pauses
|
||||
|
||||
def test_parse_pause_after(self):
|
||||
r = rparse.parse({}, "400,pa:10")
|
||||
r = rparse.parse({}, "400,pa10")
|
||||
assert (sys.maxint, 10) in r.pauses
|
||||
|
||||
def test_parse_pause_random(self):
|
||||
r = rparse.parse({}, "400,pr:10")
|
||||
r = rparse.parse({}, "400,pr10")
|
||||
assert ("random", 10) in r.pauses
|
||||
|
||||
|
||||
class uResponse(libpry.AutoTree):
|
||||
def dummy_response(self):
|
||||
return rparse.parse({}, "400:msg")
|
||||
return rparse.parse({}, "400'msg'")
|
||||
|
||||
def test_response(self):
|
||||
r = rparse.parse({}, "400:msg")
|
||||
r = rparse.parse({}, "400'msg'")
|
||||
assert r.code == 400
|
||||
assert r.msg == "msg"
|
||||
|
||||
r = rparse.parse({}, "400:msg,b:!100b")
|
||||
r = rparse.parse({}, "400'msg',b!100b")
|
||||
assert r.msg == "msg"
|
||||
assert r.body[:]
|
||||
assert str(r)
|
||||
|
||||
def test_ready_randoms(self):
|
||||
r = rparse.parse({}, "400:msg")
|
||||
r = rparse.parse({}, "400'msg'")
|
||||
|
||||
x = [(0, 5)]
|
||||
assert r.ready_randoms(100, x) == x
|
||||
@ -246,7 +245,7 @@ class uResponse(libpry.AutoTree):
|
||||
|
||||
def test_write_values(self):
|
||||
tst = "foo"*1025
|
||||
r = rparse.parse({}, "400:msg")
|
||||
r = rparse.parse({}, "400'msg'")
|
||||
|
||||
s = DummyRequest()
|
||||
r.write_values(s, [tst], [], None)
|
||||
@ -254,7 +253,7 @@ class uResponse(libpry.AutoTree):
|
||||
|
||||
def test_write_values_pauses(self):
|
||||
tst = "".join(str(i) for i in range(10))
|
||||
r = rparse.parse({}, "400:msg")
|
||||
r = rparse.parse({}, "400'msg'")
|
||||
|
||||
for i in range(2, 10):
|
||||
s = DummyRequest()
|
||||
@ -274,7 +273,7 @@ class uResponse(libpry.AutoTree):
|
||||
|
||||
def test_render(self):
|
||||
s = DummyRequest()
|
||||
r = rparse.parse({}, "400:msg")
|
||||
r = rparse.parse({}, "400'msg'")
|
||||
r.render(s)
|
||||
|
||||
def test_length(self):
|
||||
@ -282,9 +281,9 @@ class uResponse(libpry.AutoTree):
|
||||
s = DummyRequest()
|
||||
x.render(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({}, "400'msg'"))
|
||||
testlen(rparse.parse({}, "400'msg',h'foo':'bar'"))
|
||||
testlen(rparse.parse({}, "400'msg',h'foo':'bar',b!100b"))
|
||||
|
||||
|
||||
tests = [
|
||||
|
Loading…
Reference in New Issue
Block a user