Make parse_pathoc a generator

This lets us do things like this:

get:/:ir,@1:x1000000000

It will also let us expand the language to include a "repeat forever" concept.
This commit is contained in:
Aldo Cortesi 2015-06-07 13:18:33 +12:00
parent 7412ec83f5
commit 0da3e51e1c
11 changed files with 46 additions and 48 deletions

View File

@ -135,7 +135,7 @@ def make_app(noapi, debug):
try:
if is_request:
r = language.parse_pathoc(spec)[0]
r = language.parse_pathoc(spec).next()
else:
r = language.parse_pathod(spec)
except language.ParseException as v:

View File

@ -1,4 +1,5 @@
#!/usr/bin/env python
import itertools
import argparse
import os
import os.path
@ -189,7 +190,7 @@ def args_pathoc(argv, stdout=sys.stdout, stderr=sys.stderr):
data = open(r).read()
r = data
try:
reqs.extend(language.parse_pathoc(r))
reqs.append(language.parse_pathoc(r))
except language.ParseException as v:
print >> stderr, "Error parsing request spec: %s" % v.msg
print >> stderr, v.marked()

View File

@ -1,3 +1,4 @@
import itertools
import time
import pyparsing as pp
@ -28,6 +29,14 @@ def parse_pathod(s):
raise exceptions.ParseException(v.msg, v.line, v.col)
def expand(req):
if req.times:
for j in xrange(int(req.times.value)):
yield req.strike_token("times")
else:
yield req
def parse_pathoc(s):
"""
May raise ParseException
@ -47,14 +56,7 @@ def parse_pathoc(s):
).parseString(s, parseAll=True)
except pp.ParseException as v:
raise exceptions.ParseException(v.msg, v.line, v.col)
expanded = []
for i in reqs:
if i.times:
for j in range(int(i.times.value)):
expanded.append(i.strike_token("times"))
else:
expanded.append(i)
return expanded
return itertools.chain(*[expand(i) for i in reqs])
def parse_websocket_frame(s):

View File

@ -1,5 +1,6 @@
import sys
import os
import itertools
import hashlib
import Queue
import random
@ -287,7 +288,7 @@ class Pathoc(tcp.TCPClient):
"""
with self.log() as log:
if isinstance(r, basestring):
r = language.parse_pathoc(r)[0]
r = language.parse_pathoc(r).next()
log(">> %s" % r)
try:
language.serve(r, self.wfile, self.settings)
@ -330,7 +331,7 @@ class Pathoc(tcp.TCPClient):
"""
with self.log() as log:
if isinstance(r, basestring):
r = language.parse_pathoc(r)[0]
r = language.parse_pathoc(r).next()
log(">> %s" % r)
resp, req = None, None
try:
@ -369,7 +370,7 @@ class Pathoc(tcp.TCPClient):
May raise http.HTTPError, tcp.NetLibError
"""
if isinstance(r, basestring):
r = language.parse_pathoc(r)[0]
r = language.parse_pathoc(r).next()
if isinstance(r, language.http.Request):
if r.ws:
return self.websocket_start(r, self.websocket_get_frame)
@ -388,17 +389,13 @@ def main(args): # pragma: nocover
while True:
if cnt == args.repeat and args.repeat != 0:
break
if trycount > args.memolimit:
print >> sys.stderr, "Memo limit exceeded..."
return
if args.wait and cnt != 0:
time.sleep(args.wait)
cnt += 1
playlist = itertools.chain(*args.requests)
if args.random:
playlist = [random.choice(args.requests)]
else:
playlist = args.requests
playlist = random.choice(args.requests)
p = Pathoc(
(args.host, args.port),
ssl = args.ssl,
@ -414,22 +411,6 @@ def main(args): # pragma: nocover
ignoretimeout = args.ignoretimeout,
showsummary = True
)
if args.explain or args.memo:
playlist = [
i.freeze(p.settings) for i in playlist
]
if args.memo:
newlist = []
for spec in playlist:
h = hashlib.sha256(spec.spec()).digest()
if h not in memo:
memo.add(h)
newlist.append(spec)
playlist = newlist
if not playlist:
trycount += 1
continue
trycount = 0
try:
p.connect(args.connect_to, args.showssl)
@ -442,6 +423,20 @@ def main(args): # pragma: nocover
if args.timeout:
p.settimeout(args.timeout)
for spec in playlist:
if args.explain or args.memo:
spec = spec.freeze(p.settings)
if args.memo:
h = hashlib.sha256(spec.spec()).digest()
if h not in memo:
trycount = 0
memo.add(h)
else:
trycount += 1
if trycount > args.memolimit:
print >> sys.stderr, "Memo limit exceeded..."
return
else:
continue
try:
ret = p.request(spec)
if ret and args.oneshot:

View File

@ -75,7 +75,7 @@ class PathodHandler(tcp.BaseHandler):
def handle_sni(self, connection):
self.sni = connection.get_servername()
def serve_crafted(self, crafted):
def http_serve_crafted(self, crafted):
error, crafted = self.server.check_policy(
crafted, self.settings
)
@ -304,7 +304,7 @@ class PathodHandler(tcp.BaseHandler):
if anchor_spec:
lg("crafting spec: %s" % anchor_spec)
nexthandler, retlog["response"] = self.serve_crafted(
nexthandler, retlog["response"] = self.http_serve_crafted(
anchor_spec
)
if nexthandler and websocket_key:

View File

@ -135,7 +135,7 @@ def test_pathoc(perror):
tutils.test_data.path("data/request")
]
)
assert len(a.requests) == 1
assert len(list(a.requests)) == 1
a = cmdline.args_pathod(
[

View File

@ -5,7 +5,7 @@ from libpathod import language
def parse_request(s):
return language.parse_pathoc(s)[0]
return language.parse_pathoc(s).next()
def test_unique_name():

View File

@ -6,11 +6,11 @@ import nose.tools as nt
def parse_request(s):
return language.parse_pathoc(s)[0]
return language.parse_pathoc(s).next()
def test_times():
reqs = language.parse_pathoc("get:/:x5")
reqs = list(language.parse_pathoc("get:/:x5"))
assert len(reqs) == 5
assert not reqs[0].times

View File

@ -6,7 +6,7 @@ import tutils
def parse_request(s):
return language.parse_pathoc(s)[0]
return language.parse_pathoc(s).next()
def test_make_error_response():
@ -32,7 +32,7 @@ class TestRequest:
assert len(r.path.string()) == 1024
def test_multiple(self):
r = language.parse_pathoc("GET:/ PUT:/")
r = list(language.parse_pathoc("GET:/ PUT:/"))
assert r[0].method.string() == "GET"
assert r[1].method.string() == "PUT"
assert len(r) == 2
@ -52,7 +52,7 @@ class TestRequest:
ir,@1
"""
r = language.parse_pathoc(l)
r = list(language.parse_pathoc(l))
assert len(r) == 2
assert r[0].method.string() == "GET"
assert r[1].method.string() == "PUT"
@ -61,14 +61,14 @@ class TestRequest:
get:"http://localhost:9999/p/200":ir,@1
get:"http://localhost:9999/p/200":ir,@2
"""
r = language.parse_pathoc(l)
r = list(language.parse_pathoc(l))
assert len(r) == 2
assert r[0].method.string() == "GET"
assert r[1].method.string() == "GET"
def test_nested_response(self):
l = "get:/p:s'200'"
r = language.parse_pathoc(l)
r = list(language.parse_pathoc(l))
assert len(r) == 1
assert len(r[0].tokens) == 3
assert isinstance(r[0].tokens[2], http.NestedResponse)

View File

@ -6,7 +6,7 @@ import tutils
def parse_request(s):
return language.parse_pathoc(s)[0]
return language.parse_pathoc(s).next()
class TestWebsocketFrame:

View File

@ -73,7 +73,7 @@ class _TestDaemon:
if timeout:
c.settimeout(timeout)
for i in requests:
r = language.parse_pathoc(i)[0]
r = language.parse_pathoc(i).next()
if explain:
r = r.freeze(language.Settings())
try: