aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libpathod/language.py58
-rw-r--r--test/test_language.py22
2 files changed, 56 insertions, 24 deletions
diff --git a/libpathod/language.py b/libpathod/language.py
index 5d6471e6..446c1823 100644
--- a/libpathod/language.py
+++ b/libpathod/language.py
@@ -1,4 +1,5 @@
import operator, string, random, mmap, os, time, copy
+import abc
from email.utils import formatdate
import contrib.pyparsing as pp
from netlib import http_status, tcp
@@ -292,7 +293,22 @@ Offset = pp.MatchFirst(
)
-class _Header:
+class _Component(object):
+ __metaclass__ = abc.ABCMeta
+ @abc.abstractmethod
+ def values(self, settings): return None # pragma: no cover
+
+ @abc.abstractmethod
+ def expr(klass): return None # pragma: no cover
+
+ @abc.abstractmethod
+ def accept(self, settings): return None # pragma: no cover
+
+ def string(self, settings=None):
+ return "".join(i[:] for i in self.values(settings or {}))
+
+
+class _Header(_Component):
def __init__(self, key, value):
self.key, self.value = key, value
@@ -340,7 +356,7 @@ class ShortcutLocation(_Header):
return e.setParseAction(lambda x: klass(*x))
-class Body:
+class Body(_Component):
def __init__(self, value):
self.value = value
@@ -369,23 +385,29 @@ class Raw:
return e.setParseAction(lambda x: klass(*x))
-class Path:
+class Path(_Component):
def __init__(self, value):
if isinstance(value, basestring):
value = ValueLiteral(value)
self.value = value
def accept(self, settings, r):
- r.path = self.value.get_generator(settings)
+ r.path = self
@classmethod
def expr(klass):
e = NakedValue.copy()
return e.setParseAction(lambda x: klass(*x))
+ def values(self, settings):
+ return [
+ self.value.get_generator(settings),
+ ]
+
-class Method:
+
+class Method(_Component):
methods = [
"get",
"head",
@@ -405,7 +427,7 @@ class Method:
self.value = value
def accept(self, settings, r):
- r.method = self.value.get_generator(settings)
+ r.method = self
@classmethod
def expr(klass):
@@ -415,6 +437,11 @@ class Method:
spec = spec.setParseAction(lambda x: klass(*x))
return spec
+ def values(self, settings):
+ return [
+ self.value.get_generator(settings)
+ ]
+
class _Action:
"""
@@ -546,7 +573,7 @@ class Message:
"""
Calculate the length of the base message without any applied actions.
"""
- l = sum(len(x) for x in self.preamble())
+ l = sum(len(x) for x in self.preamble(settings))
l += 2
for h in self.headervals(settings, request_host):
l += len(h)
@@ -625,7 +652,7 @@ class Message:
hdrs = self.headervals(settings, request_host)
- vals = self.preamble()
+ vals = self.preamble(settings)
vals.append("\r\n")
vals.extend(hdrs)
vals.append("\r\n")
@@ -673,7 +700,7 @@ class Response(Message):
self.code = None
self.msg = None
- def preamble(self):
+ def preamble(self, settings):
return [self.version, " ", str(self.code), " ", self.msg]
@classmethod
@@ -711,8 +738,13 @@ class Request(Message):
self.method = None
self.path = None
- def preamble(self):
- return [self.method, " ", self.path, " ", self.version]
+ def preamble(self, settings):
+ v = self.method.values(settings)
+ v.append(" ")
+ v.extend(self.path.values(settings))
+ v.append(" ")
+ v.append(self.version)
+ return v
@classmethod
def expr(klass):
@@ -728,9 +760,9 @@ class Request(Message):
)
return resp
- def __str__(self):
+ def string(self, values=None):
parts = [
- "%s %s"%(self.method[:], self.path[:])
+ "%s %s"%(self.method.string(values), self.path.string(values))
]
return "\n".join(parts)
diff --git a/test/test_language.py b/test/test_language.py
index 54f96d51..aba67274 100644
--- a/test/test_language.py
+++ b/test/test_language.py
@@ -324,7 +324,7 @@ class TestParseRequest:
p = tutils.test_data.path("data")
d = dict(staticdir=p)
r = language.parse_request(d, "+request")
- assert r.path == "/foo"
+ assert r.path.values({})[0][:] == "/foo"
def test_nonascii(self):
tutils.raises("ascii", language.parse_request, {}, "get:\xf0")
@@ -334,21 +334,21 @@ class TestParseRequest:
def test_simple(self):
r = language.parse_request({}, 'GET:"/foo"')
- assert r.method == "GET"
- assert r.path == "/foo"
+ assert r.method.string() == "GET"
+ assert r.path.string() == "/foo"
r = language.parse_request({}, 'GET:/foo')
- assert r.path == "/foo"
+ assert r.path.string() == "/foo"
r = language.parse_request({}, 'GET:@1k')
- assert len(r.path) == 1024
+ assert len(r.path.string()) == 1024
def test_render(self):
s = cStringIO.StringIO()
r = language.parse_request({}, "GET:'/foo'")
assert r.serve(s, {}, "foo.com")
- def test_str(self):
+ def test_string(self):
r = language.parse_request({}, 'GET:"/foo"')
- assert str(r)
+ assert r.string()
def test_multiline(self):
l = """
@@ -357,8 +357,8 @@ class TestParseRequest:
ir,@1
"""
r = language.parse_request({}, l)
- assert r.method == "GET"
- assert r.path == "/foo"
+ assert r.method.string() == "GET"
+ assert r.path.string() == "/foo"
assert r.actions
@@ -374,8 +374,8 @@ class TestParseRequest:
ir,@1
"""
r = language.parse_request({}, l)
- assert r.method == "GET"
- assert r.path.s.endswith("bar")
+ assert r.method.string() == "GET"
+ assert r.path.string().endswith("bar")
assert r.actions