mirror of
https://github.com/Grasscutters/mitmproxy.git
synced 2024-11-27 02:24:18 +00:00
Allow nesting of pathod response specs in pathoc specs
This opens the door to really neat, repeatable, client-side driven fuzzing, especially of proxies.
This commit is contained in:
parent
c00ae41486
commit
fc1fc80469
@ -1,3 +1,4 @@
|
|||||||
|
from __future__ import print_function
|
||||||
import operator
|
import operator
|
||||||
import string
|
import string
|
||||||
import random
|
import random
|
||||||
@ -6,7 +7,6 @@ import os
|
|||||||
import time
|
import time
|
||||||
import copy
|
import copy
|
||||||
import abc
|
import abc
|
||||||
from email.utils import formatdate
|
|
||||||
import contrib.pyparsing as pp
|
import contrib.pyparsing as pp
|
||||||
from netlib import http_status, tcp, http_uastrings
|
from netlib import http_status, tcp, http_uastrings
|
||||||
|
|
||||||
@ -527,6 +527,43 @@ class Body(_Component):
|
|||||||
return Body(self.value.freeze(settings))
|
return Body(self.value.freeze(settings))
|
||||||
|
|
||||||
|
|
||||||
|
class PathodSpec(_Token):
|
||||||
|
def __init__(self, value):
|
||||||
|
self.value = value
|
||||||
|
try:
|
||||||
|
self.parsed = Response(
|
||||||
|
Response.expr().parseString(
|
||||||
|
value.val,
|
||||||
|
parseAll=True
|
||||||
|
)
|
||||||
|
)
|
||||||
|
except pp.ParseException, v:
|
||||||
|
raise ParseException(v.msg, v.line, v.col)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def expr(klass):
|
||||||
|
e = pp.Literal("s").suppress()
|
||||||
|
e = e + ValueLiteral.expr()
|
||||||
|
return e.setParseAction(lambda x: klass(*x))
|
||||||
|
|
||||||
|
def values(self, settings):
|
||||||
|
return [
|
||||||
|
self.value.get_generator(settings),
|
||||||
|
]
|
||||||
|
|
||||||
|
def quote(self, s):
|
||||||
|
quotechar = s[0]
|
||||||
|
s = s[1:-1]
|
||||||
|
s = s.replace(quotechar, "\\" + quotechar)
|
||||||
|
return quotechar + s + quotechar
|
||||||
|
|
||||||
|
def spec(self):
|
||||||
|
return "s%s"%(self.quote(self.value.spec()))
|
||||||
|
|
||||||
|
def freeze(self, settings):
|
||||||
|
return PathodSpec(ValueLiteral(self.parsed.freeze(settings).spec()))
|
||||||
|
|
||||||
|
|
||||||
class Path(_Component):
|
class Path(_Component):
|
||||||
def __init__(self, value):
|
def __init__(self, value):
|
||||||
if isinstance(value, basestring):
|
if isinstance(value, basestring):
|
||||||
@ -934,7 +971,8 @@ class Request(_Message):
|
|||||||
InjectAt,
|
InjectAt,
|
||||||
ShortcutContentType,
|
ShortcutContentType,
|
||||||
ShortcutUserAgent,
|
ShortcutUserAgent,
|
||||||
Raw
|
Raw,
|
||||||
|
PathodSpec,
|
||||||
)
|
)
|
||||||
logattrs = ["method", "path", "body"]
|
logattrs = ["method", "path", "body"]
|
||||||
|
|
||||||
@ -946,10 +984,16 @@ class Request(_Message):
|
|||||||
def path(self):
|
def path(self):
|
||||||
return self._get_token(Path)
|
return self._get_token(Path)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def pathodspec(self):
|
||||||
|
return self._get_token(PathodSpec)
|
||||||
|
|
||||||
def preamble(self, settings):
|
def preamble(self, settings):
|
||||||
v = self.method.values(settings)
|
v = self.method.values(settings)
|
||||||
v.append(" ")
|
v.append(" ")
|
||||||
v.extend(self.path.values(settings))
|
v.extend(self.path.values(settings))
|
||||||
|
if self.pathodspec:
|
||||||
|
v.append(self.pathodspec.parsed.spec())
|
||||||
v.append(" ")
|
v.append(" ")
|
||||||
v.append(self.version)
|
v.append(self.version)
|
||||||
return v
|
return v
|
||||||
|
@ -223,6 +223,29 @@ class TestMisc:
|
|||||||
s = v.spec()
|
s = v.spec()
|
||||||
assert s == e.parseString(s)[0].spec()
|
assert s == e.parseString(s)[0].spec()
|
||||||
|
|
||||||
|
def test_pathodspec(self):
|
||||||
|
e = language.PathodSpec.expr()
|
||||||
|
v = e.parseString("s'200'")[0]
|
||||||
|
assert v.value.val == "200"
|
||||||
|
tutils.raises(
|
||||||
|
language.ParseException,
|
||||||
|
e.parseString,
|
||||||
|
"s'foo'"
|
||||||
|
)
|
||||||
|
|
||||||
|
v = e.parseString('s"200:b@1"')[0]
|
||||||
|
assert "@1" in v.spec()
|
||||||
|
f = v.freeze({})
|
||||||
|
assert "@1" not in f.spec()
|
||||||
|
|
||||||
|
r = parse_request('GET:"/foo":s"200"')
|
||||||
|
assert "200" in r.preamble({})
|
||||||
|
|
||||||
|
f = r.freeze({})
|
||||||
|
assert parse_request(f.spec())
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def test_code(self):
|
def test_code(self):
|
||||||
e = language.Code.expr()
|
e = language.Code.expr()
|
||||||
v = e.parseString("200")[0]
|
v = e.parseString("200")[0]
|
||||||
@ -661,14 +684,12 @@ class TestResponse:
|
|||||||
language.serve(r, s, {})
|
language.serve(r, s, {})
|
||||||
v = s.getvalue()
|
v = s.getvalue()
|
||||||
assert "Content-Length" in v
|
assert "Content-Length" in v
|
||||||
assert "Date" in v
|
|
||||||
|
|
||||||
s = cStringIO.StringIO()
|
s = cStringIO.StringIO()
|
||||||
r = language.parse_response("400:b'foo':r")
|
r = language.parse_response("400:b'foo':r")
|
||||||
language.serve(r, s, {})
|
language.serve(r, s, {})
|
||||||
v = s.getvalue()
|
v = s.getvalue()
|
||||||
assert not "Content-Length" in v
|
assert not "Content-Length" in v
|
||||||
assert not "Date" in v
|
|
||||||
|
|
||||||
def test_length(self):
|
def test_length(self):
|
||||||
def testlen(x):
|
def testlen(x):
|
||||||
|
@ -59,8 +59,11 @@ class _TestDaemon:
|
|||||||
c.settimeout(timeout)
|
c.settimeout(timeout)
|
||||||
s = cStringIO.StringIO()
|
s = cStringIO.StringIO()
|
||||||
for i in requests:
|
for i in requests:
|
||||||
|
r = language.parse_requests(i)[0]
|
||||||
|
if explain:
|
||||||
|
r = r.freeze({})
|
||||||
c.print_request(
|
c.print_request(
|
||||||
language.parse_requests(i)[0],
|
r,
|
||||||
showreq = showreq,
|
showreq = showreq,
|
||||||
showresp = showresp,
|
showresp = showresp,
|
||||||
explain = explain,
|
explain = explain,
|
||||||
|
Loading…
Reference in New Issue
Block a user