Refactoring: canonical storage of a message is now the sequence of tokens that defines it.

We use a set of accessor properties to ease access to tokens. We can now ditch
the .accept() methods.
This commit is contained in:
Aldo Cortesi 2012-10-29 15:16:44 +13:00
parent 882969086c
commit 8741600ce7
2 changed files with 68 additions and 87 deletions

View File

@ -309,18 +309,8 @@ class _Spec(object):
""" """
return None return None
@abc.abstractmethod
def accept(self, r): # pragma: no cover
"""
Notifies the component to register itself with message r.
"""
return None
class Raw(_Spec): class Raw(_Spec):
def accept(self, r):
r.raw = True
@classmethod @classmethod
def expr(klass): def expr(klass):
e = pp.Literal("r").suppress() e = pp.Literal("r").suppress()
@ -357,9 +347,6 @@ class _Header(_Component):
"\r\n", "\r\n",
] ]
def accept(self, r):
r.headers.append(self)
class Header(_Header): class Header(_Header):
@classmethod @classmethod
@ -397,9 +384,6 @@ class Body(_Component):
def __init__(self, value): def __init__(self, value):
self.value = value self.value = value
def accept(self, r):
r.body = self
@classmethod @classmethod
def expr(klass): def expr(klass):
e = pp.Literal("b").suppress() e = pp.Literal("b").suppress()
@ -418,9 +402,6 @@ class Path(_Component):
value = ValueLiteral(value) value = ValueLiteral(value)
self.value = value self.value = value
def accept(self, r):
r.path = self
@classmethod @classmethod
def expr(klass): def expr(klass):
e = NakedValue.copy() e = NakedValue.copy()
@ -451,9 +432,6 @@ class Method(_Component):
value = ValueLiteral(value.upper()) value = ValueLiteral(value.upper())
self.value = value self.value = value
def accept(self, r):
r.method = self
@classmethod @classmethod
def expr(klass): def expr(klass):
parts = [pp.CaselessLiteral(i) for i in klass.methods] parts = [pp.CaselessLiteral(i) for i in klass.methods]
@ -472,9 +450,6 @@ class Code(_Component):
def __init__(self, code): def __init__(self, code):
self.code = str(code) self.code = str(code)
def accept(self, r):
r.code = self
@classmethod @classmethod
def expr(klass): def expr(klass):
e = v_integer.copy() e = v_integer.copy()
@ -488,8 +463,6 @@ class Reason(_Component):
def __init__(self, value): def __init__(self, value):
self.value = value self.value = value
def accept(self, r):
r.reason = self
@classmethod @classmethod
def expr(klass): def expr(klass):
@ -529,9 +502,6 @@ class _Action(_Spec):
def __repr__(self): def __repr__(self):
return self.spec() return self.spec()
def accept(self, r):
r.actions.append(self)
@abc.abstractmethod @abc.abstractmethod
def spec(self): # pragma: no cover def spec(self): # pragma: no cover
pass pass
@ -610,11 +580,32 @@ class InjectAt(_Action):
class _Message(object): class _Message(object):
__metaclass__ = abc.ABCMeta __metaclass__ = abc.ABCMeta
version = "HTTP/1.1" version = "HTTP/1.1"
def __init__(self): def __init__(self, tokens):
self.body = None self.tokens = tokens
self.headers = []
self.actions = [] def _get_tokens(self, klass):
self.raw = False return [i for i in self.tokens if isinstance(i, klass)]
def _get_token(self, klass):
l = self._get_tokens(klass)
if l:
return l[0]
@property
def raw(self):
return bool(self._get_token(Raw))
@property
def actions(self):
return self._get_tokens(_Action)
@property
def body(self):
return self._get_token(Body)
@property
def headers(self):
return self._get_tokens(_Header)
def length(self, settings, request_host): def length(self, settings, request_host):
""" """
@ -634,7 +625,7 @@ class _Message(object):
Modify this message to be safe for previews. Returns a list of elided actions. Modify this message to be safe for previews. Returns a list of elided actions.
""" """
pauses = [i for i in self.actions if isinstance(i, PauseAt)] pauses = [i for i in self.actions if isinstance(i, PauseAt)]
self.actions = [i for i in self.actions if not isinstance(i, PauseAt)] #self.actions = [i for i in self.actions if not isinstance(i, PauseAt)]
return pauses return pauses
def maximum_length(self, settings, request_host): def maximum_length(self, settings, request_host):
@ -738,7 +729,7 @@ class _Message(object):
Sep = pp.Optional(pp.Literal(":")).suppress() Sep = pp.Optional(pp.Literal(":")).suppress()
class Response(_Message): class _Response(_Message):
comps = ( comps = (
Body, Body,
Header, Header,
@ -751,10 +742,13 @@ class Response(_Message):
Reason Reason
) )
logattrs = ["code", "reason", "version", "body"] logattrs = ["code", "reason", "version", "body"]
def __init__(self): @property
_Message.__init__(self) def code(self):
self.code = None return self._get_token(Code)
self.reason = None
@property
def reason(self):
return self._get_token(Reason)
def preamble(self, settings): def preamble(self, settings):
l = [self.version, " "] l = [self.version, " "]
@ -779,7 +773,7 @@ class Response(_Message):
return resp return resp
class Request(_Message): class _Request(_Message):
comps = ( comps = (
Body, Body,
Header, Header,
@ -790,10 +784,13 @@ class Request(_Message):
Raw Raw
) )
logattrs = ["method", "path", "body"] logattrs = ["method", "path", "body"]
def __init__(self): @property
_Message.__init__(self) def method(self):
self.method = None return self._get_token(Method)
self.path = None
@property
def path(self):
return self._get_token(Path)
def preamble(self, settings): def preamble(self, settings):
v = self.method.values(settings) v = self.method.values(settings)
@ -818,44 +815,40 @@ class Request(_Message):
return resp return resp
class CraftedRequest(Request): class CraftedRequest(_Request):
def __init__(self, settings, spec, tokens): def __init__(self, spec, tokens):
Request.__init__(self) _Request.__init__(self, tokens)
self.spec, self.tokens = spec, tokens self.spec, self.tokens = spec, tokens
for i in tokens:
i.accept(self)
def serve(self, fp, settings, host): def serve(self, fp, settings, host):
d = Request.serve(self, fp, settings, host) d = _Request.serve(self, fp, settings, host)
d["spec"] = self.spec d["spec"] = self.spec
return d return d
class CraftedResponse(Response): class CraftedResponse(_Response):
def __init__(self, settings, spec, tokens): def __init__(self, spec, tokens):
Response.__init__(self) _Response.__init__(self, tokens)
self.spec, self.tokens = spec, tokens self.spec, self.tokens = spec, tokens
for i in tokens:
i.accept(self)
def serve(self, fp, settings): def serve(self, fp, settings):
d = Response.serve(self, fp, settings, None) d = _Response.serve(self, fp, settings, None)
d["spec"] = self.spec d["spec"] = self.spec
return d return d
class PathodErrorResponse(Response): class PathodErrorResponse(_Response):
def __init__(self, msg, body=None): def __init__(self, reason, body=None):
Response.__init__(self) tokens = [
self.code = Code("800") Code("800"),
self.msg = LiteralGenerator(msg)
self.body = Body(ValueLiteral("pathod error: " + (body or msg)))
self.headers = [
Header(ValueLiteral("Content-Type"), ValueLiteral("text/plain")), Header(ValueLiteral("Content-Type"), ValueLiteral("text/plain")),
Reason(ValueLiteral(reason)),
Body(ValueLiteral("pathod error: " + (body or reason))),
] ]
_Response.__init__(self, tokens)
def serve(self, fp, settings): def serve(self, fp, settings):
d = Response.serve(self, fp, settings, None) d = _Response.serve(self, fp, settings, None)
d["internal"] = True d["internal"] = True
return d return d
@ -888,7 +881,7 @@ def parse_response(settings, s):
if s.startswith(FILESTART): if s.startswith(FILESTART):
s = read_file(settings, s) s = read_file(settings, s)
try: try:
return CraftedResponse(settings, s, Response.expr().parseString(s, parseAll=True)) return CraftedResponse(s, _Response.expr().parseString(s, parseAll=True))
except pp.ParseException, v: except pp.ParseException, v:
raise ParseException(v.msg, v.line, v.col) raise ParseException(v.msg, v.line, v.col)
@ -904,6 +897,6 @@ def parse_request(settings, s):
if s.startswith(FILESTART): if s.startswith(FILESTART):
s = read_file(settings, s) s = read_file(settings, s)
try: try:
return CraftedRequest(settings, s, Request.expr().parseString(s, parseAll=True)) return CraftedRequest(s, _Request.expr().parseString(s, parseAll=True))
except pp.ParseException, v: except pp.ParseException, v:
raise ParseException(v.msg, v.line, v.col) raise ParseException(v.msg, v.line, v.col)

View File

@ -542,32 +542,20 @@ class TestResponse:
testlen(language.parse_response({}, "400:m'msg':h'foo'='bar':b@100b")) testlen(language.parse_response({}, "400:m'msg':h'foo'='bar':b@100b"))
def test_maximum_length(self): def test_maximum_length(self):
def testlen(x, actions): def testlen(x):
s = cStringIO.StringIO() s = cStringIO.StringIO()
m = x.maximum_length({}, None) m = x.maximum_length({}, None)
x.serve(s, {}) x.serve(s, {})
assert m >= len(s.getvalue()) assert m >= len(s.getvalue())
r = language.parse_response({}, "400:m'msg':b@100") r = language.parse_response({}, "400:m'msg':b@100:d0")
testlen(r)
actions = [ r = language.parse_response({}, "400:m'msg':b@100:d0:i0,'foo'")
language.DisconnectAt(0) testlen(r)
]
r.actions = actions
testlen(r, actions)
actions = [ r = language.parse_response({}, "400:m'msg':b@100:d0:i0,'foo'")
language.DisconnectAt(0), testlen(r)
language.InjectAt(0, language.ValueLiteral("foo"))
]
r.actions = actions
testlen(r, actions)
actions = [
language.InjectAt(0, language.ValueLiteral("foo"))
]
r.actions = actions
testlen(r, actions)
def test_render(self): def test_render(self):
r = language.parse_response({}, "400:p0,100:dr") r = language.parse_response({}, "400:p0,100:dr")