aboutsummaryrefslogtreecommitdiffstats
path: root/libpathod
diff options
context:
space:
mode:
Diffstat (limited to 'libpathod')
-rw-r--r--libpathod/language/base.py42
-rw-r--r--libpathod/language/http.py16
-rw-r--r--libpathod/language/websockets.py23
3 files changed, 70 insertions, 11 deletions
diff --git a/libpathod/language/base.py b/libpathod/language/base.py
index 41855da3..725a0d42 100644
--- a/libpathod/language/base.py
+++ b/libpathod/language/base.py
@@ -291,14 +291,19 @@ class OptionsOrValue(_Component):
Can be any of a specified set of options, or a value specifier.
"""
preamble = ""
+ options = []
def __init__(self, value):
# If it's a string, we were passed one of the options, so we lower-case
# it to be canonical. The user can specify a different case by using a
# string value literal.
self.option_used = False
if isinstance(value, basestring):
- value = TokValueLiteral(value.lower())
- self.option_used = True
+ for i in self.options:
+ # Find the exact option value in a case-insensitive way
+ if i.lower() == value.lower():
+ self.option_used = True
+ value = TokValueLiteral(i)
+ break
self.value = value
@classmethod
@@ -369,3 +374,36 @@ class Value(_Component):
def freeze(self, settings):
return self.__class__(self.value.freeze(settings))
+
+
+class IntField(_Component):
+ """
+ An integer field, where values can optionally specified by name.
+ """
+ names = {}
+ max = 16
+ preamble = ""
+
+ def __init__(self, value):
+ self.origvalue = value
+ self.value = self.names.get(value, value)
+ if self.value > self.max:
+ raise exceptions.ParseException(
+ "Value can't exceed %s"%self.max, 0, 0
+ )
+
+ @classmethod
+ def expr(klass):
+ parts = [pp.CaselessLiteral(i) for i in klass.names.keys()]
+ m = pp.MatchFirst(parts)
+ spec = m | v_integer.copy()
+ spec = spec.setParseAction(lambda x: klass(*x))
+ if klass.preamble:
+ spec = pp.Literal(klass.preamble).suppress() + spec
+ return spec
+
+ def values(self, settings):
+ return [str(self.value)]
+
+ def spec(self):
+ return "%s%s"%(self.preamble, self.origvalue)
diff --git a/libpathod/language/http.py b/libpathod/language/http.py
index ba43a367..94de7237 100644
--- a/libpathod/language/http.py
+++ b/libpathod/language/http.py
@@ -34,14 +34,14 @@ class Body(base.Value):
class Method(base.OptionsOrValue):
options = [
- "get",
- "head",
- "post",
- "put",
- "delete",
- "options",
- "trace",
- "connect",
+ "GET",
+ "HEAD",
+ "POST",
+ "PUT",
+ "DELETE",
+ "OPTIONS",
+ "TRACE",
+ "CONNECT",
]
diff --git a/libpathod/language/websockets.py b/libpathod/language/websockets.py
index ae755f30..ddffdab9 100644
--- a/libpathod/language/websockets.py
+++ b/libpathod/language/websockets.py
@@ -17,6 +17,19 @@ class WF(base.CaselessLiteral):
TOK = "wf"
+class Code(base.IntField):
+ names = {
+ "continue": netlib.websockets.OPCODE.CONTINUE,
+ "text": netlib.websockets.OPCODE.TEXT,
+ "binary": netlib.websockets.OPCODE.BINARY,
+ "close": netlib.websockets.OPCODE.CLOSE,
+ "ping": netlib.websockets.OPCODE.PING,
+ "pong": netlib.websockets.OPCODE.PONG,
+ }
+ max = 15
+ preamble = "c"
+
+
class Body(base.Value):
preamble = "b"
@@ -24,6 +37,7 @@ class Body(base.Value):
class WebsocketFrame(message.Message):
comps = (
Body,
+ Code,
actions.PauseAt,
actions.DisconnectAt,
actions.InjectAt
@@ -37,6 +51,10 @@ class WebsocketFrame(message.Message):
def body(self):
return self.tok(Body)
+ @property
+ def code(self):
+ return self.tok(Code)
+
@classmethod
def expr(klass):
parts = [i.expr() for i in klass.comps]
@@ -59,10 +77,13 @@ class WebsocketFrame(message.Message):
else:
bodygen = None
length = 0
- frame = netlib.websockets.FrameHeader(
+ frameparts = dict(
mask = True,
payload_length = length
)
+ if self.code:
+ frameparts["opcode"] = self.code.value
+ frame = netlib.websockets.FrameHeader(**frameparts)
vals = [frame.to_bytes()]
if self.body:
masker = netlib.websockets.Masker(frame.masking_key)