Simple request spec parsing.

This commit is contained in:
Aldo Cortesi 2012-06-24 17:47:55 +12:00
parent 75f06d56cd
commit f8622ea914
3 changed files with 67 additions and 10 deletions

View File

@ -1,6 +1,7 @@
import operator, string, random, mmap, os, time
import contrib.pyparsing as pp
from netlib import http_status
import utils
BLOCKSIZE = 1024
@ -305,7 +306,7 @@ class Method:
# it to be canonical. The user can specify a different case by using a
# string value literal.
if isinstance(value, basestring):
value = value.upper()
value = ValueLiteral(value.upper())
self.value = value
def accept(self, settings, r):
@ -406,6 +407,46 @@ class Code:
return e.setParseAction(lambda x: klass(*x))
class Request:
comps = (
Body,
Header,
PauseAt,
DisconnectAt,
ShortcutContentType,
)
version = "HTTP/1.1"
body = LiteralGenerator("")
def __init__(self):
self.headers = []
self.actions = []
@classmethod
def expr(klass):
parts = [i.expr() for i in klass.comps]
atom = pp.MatchFirst(parts)
resp = pp.And(
[
Method.expr(),
pp.ZeroOrMore(pp.Literal(":").suppress() + atom)
]
)
return resp
class CraftedRequest(Request):
def __init__(self, settings, spec, tokens):
Request.__init__(self)
self.spec, self.tokens = spec, tokens
for i in tokens:
i.accept(settings, self)
def serve(self, fp):
d = Request.serve(self, fp)
d["spec"] = self.spec
return d
class Response:
comps = (
Body,
@ -423,12 +464,6 @@ class Response:
self.headers = []
self.actions = []
def get_header(self, hdr):
for k, v in self.headers:
if k[:len(hdr)].lower() == hdr:
return v
return None
@classmethod
def expr(klass):
parts = [i.expr() for i in klass.comps]
@ -454,7 +489,7 @@ class Response:
def serve(self, fp):
started = time.time()
if self.body and not self.get_header("Content-Length"):
if self.body and not utils.get_header("Content-Length", self.headers):
self.headers.append(
(
LiteralGenerator("Content-Length"),
@ -540,3 +575,10 @@ def parse_response(settings, s):
return CraftedResponse(settings, s, Response.expr().parseString(s, parseAll=True))
except pp.ParseException, v:
raise ParseException(v.msg, v.line, v.col)
def parse_request(settings, s):
try:
return CraftedRequest(settings, s, Request.expr().parseString(s, parseAll=True))
except pp.ParseException, v:
raise ParseException(v.msg, v.line, v.col)

View File

@ -1,6 +1,15 @@
import os, re
import rparse
def get_header(val, headers):
"""
Header keys may be Values, so we have to "generate" them as we try the match.
"""
for k, v in headers:
if len(k) == len(val) and k[:].lower() == val:
return v
return None
def parse_anchor_spec(s):
"""

View File

@ -188,7 +188,13 @@ class TestPauses:
assert r.actions[0] == (10, "pause", 10)
class TestParse:
class TestParseRequest:
def test_simple(self):
r = rparse.parse_request({}, "GET")
assert r.method == "GET"
class TestParseResponse:
def test_parse_err(self):
tutils.raises(rparse.ParseException, rparse.parse_response, {}, "400:msg,b:")
try:
@ -199,7 +205,7 @@ class TestParse:
def test_parse_header(self):
r = rparse.parse_response({}, '400:h"foo"="bar"')
assert r.get_header("foo") == "bar"
assert utils.get_header("foo", r.headers)
def test_parse_pause_before(self):
r = rparse.parse_response({}, "400:p10,0")