Add a raw modifier to requests and responses, which turn off automatic additions.

For now, this just turns off adding a Content-Length header when a body is specified.
This commit is contained in:
Aldo Cortesi 2012-07-24 12:18:14 +12:00
parent 2dd2137d44
commit dbed251fb9
2 changed files with 41 additions and 12 deletions

View File

@ -8,6 +8,7 @@ TRUNCATE = 1024
class FileAccessDenied(Exception): pass class FileAccessDenied(Exception): pass
class ParseException(Exception): class ParseException(Exception):
def __init__(self, msg, s, col): def __init__(self, msg, s, col):
Exception.__init__(self) Exception.__init__(self)
@ -22,7 +23,6 @@ class ParseException(Exception):
return "%s at offset %s of %s"%(self.msg, self.col, repr(self.s)) return "%s at offset %s of %s"%(self.msg, self.col, repr(self.s))
def actions_log(lst): def actions_log(lst):
ret = [] ret = []
for i in lst: for i in lst:
@ -344,6 +344,16 @@ class Body:
return e.setParseAction(lambda x: klass(*x)) return e.setParseAction(lambda x: klass(*x))
class Raw:
def accept(self, settings, r):
r.raw = True
@classmethod
def expr(klass):
e = pp.Literal("r").suppress()
return e.setParseAction(lambda x: klass(*x))
class Path: class Path:
def __init__(self, value): def __init__(self, value):
if isinstance(value, basestring): if isinstance(value, basestring):
@ -496,6 +506,12 @@ class Code:
class Message: class Message:
version = "HTTP/1.1" version = "HTTP/1.1"
def __init__(self):
self.body = LiteralGenerator("")
self.headers = []
self.actions = []
self.raw = False
def length(self): def length(self):
""" """
Calculate the length of the base message without any applied actions. Calculate the length of the base message without any applied actions.
@ -528,12 +544,12 @@ class Message:
fp: The file pointer to write to. fp: The file pointer to write to.
check: A function called with the effective actions (after random check: A function called with the effective actions (after random
values have been calculated). If it returns False service values have been calculated). If it returns False service proceeds,
proceeds, otherwise the return is treated as an error message to be otherwise the return is treated as an error message to be sent to
sent to the client, and service stops. the client, and service stops.
""" """
started = time.time() started = time.time()
if self.body and not utils.get_header("Content-Length", self.headers): if self.body and not self.raw and not utils.get_header("Content-Length", self.headers):
self.headers.append( self.headers.append(
( (
LiteralGenerator("Content-Length"), LiteralGenerator("Content-Length"),
@ -596,14 +612,13 @@ class Response(Message):
InjectAt, InjectAt,
ShortcutContentType, ShortcutContentType,
ShortcutLocation, ShortcutLocation,
Raw
) )
logattrs = ["code", "version"] logattrs = ["code", "version"]
def __init__(self): def __init__(self):
self.headers = [] Message.__init__(self)
self.actions = []
self.code = 200 self.code = 200
self.msg = LiteralGenerator(http_status.RESPONSES[self.code]) self.msg = LiteralGenerator(http_status.RESPONSES[self.code])
self.body = LiteralGenerator("")
def preamble(self): def preamble(self):
return [self.version, " ", str(self.code), " ", self.msg] return [self.version, " ", str(self.code), " ", self.msg]
@ -635,14 +650,13 @@ class Request(Message):
DisconnectAt, DisconnectAt,
InjectAt, InjectAt,
ShortcutContentType, ShortcutContentType,
Raw
) )
logattrs = ["method", "path"] logattrs = ["method", "path"]
def __init__(self): def __init__(self):
Message.__init__(self)
self.method = None self.method = None
self.path = None self.path = None
self.body = LiteralGenerator("")
self.headers = []
self.actions = []
def preamble(self): def preamble(self):
return [self.method, " ", self.path, " ", self.version] return [self.method, " ", self.path, " ", self.version]

View File

@ -116,6 +116,10 @@ class TestMisc:
assert e.parseString("'foo'")[0].value.val == "foo" assert e.parseString("'foo'")[0].value.val == "foo"
assert e.parseString("'get'")[0].value.val == "get" assert e.parseString("'get'")[0].value.val == "get"
def test_raw(self):
e = rparse.Raw.expr()
assert e.parseString("r")[0]
def test_body(self): def test_body(self):
e = rparse.Body.expr() e = rparse.Body.expr()
v = e.parseString("b'foo'")[0] v = e.parseString("b'foo'")[0]
@ -436,6 +440,17 @@ class TestResponse:
r = rparse.parse_response({}, "400'msg'") r = rparse.parse_response({}, "400'msg'")
assert r.serve(s) assert r.serve(s)
def test_raw(self):
s = cStringIO.StringIO()
r = rparse.parse_response({}, "400:b'foo'")
r.serve(s)
assert "Content-Length" in s.getvalue()
s = cStringIO.StringIO()
r = rparse.parse_response({}, "400:b'foo':r")
r.serve(s)
assert not "Content-Length" in s.getvalue()
def test_length(self): def test_length(self):
def testlen(x): def testlen(x):
s = cStringIO.StringIO() s = cStringIO.StringIO()