diff options
Diffstat (limited to 'libpathod/language')
-rw-r--r-- | libpathod/language/__init__.py | 24 | ||||
-rw-r--r-- | libpathod/language/base.py | 8 | ||||
-rw-r--r-- | libpathod/language/http2.py | 119 |
3 files changed, 138 insertions, 13 deletions
diff --git a/libpathod/language/__init__.py b/libpathod/language/__init__.py index c41e8602..ae9a8c76 100644 --- a/libpathod/language/__init__.py +++ b/libpathod/language/__init__.py @@ -3,7 +3,7 @@ import time import pyparsing as pp -from . import http, websockets, writer, exceptions +from . import http, http2, websockets, writer, exceptions from exceptions import * from base import Settings @@ -39,20 +39,24 @@ def parse_pathod(s): return itertools.chain(*[expand(i) for i in reqs]) -def parse_pathoc(s): +def parse_pathoc(s, use_http2=False): try: s = s.decode("ascii") except UnicodeError: raise exceptions.ParseException("Spec must be valid ASCII.", 0, 0) try: - reqs = pp.OneOrMore( - pp.Or( - [ - websockets.WebsocketClientFrame.expr(), - http.Request.expr(), - ] - ) - ).parseString(s, parseAll=True) + if use_http2: + expressions = [ + # http2.Frame.expr(), + http2.Request.expr(), + ] + else: + expressions = [ + websockets.WebsocketClientFrame.expr(), + http.Request.expr(), + ] + + reqs = pp.OneOrMore(pp.Or(expressions)).parseString(s, parseAll=True) except pp.ParseException as v: raise exceptions.ParseException(v.msg, v.line, v.col) return itertools.chain(*[expand(i) for i in reqs]) diff --git a/libpathod/language/base.py b/libpathod/language/base.py index ee5d05b5..88712d69 100644 --- a/libpathod/language/base.py +++ b/libpathod/language/base.py @@ -15,13 +15,15 @@ class Settings: staticdir = None, unconstrained_file_access = False, request_host = None, - websocket_key = None + websocket_key = None, + protocol = None, ): + self.is_client = is_client self.staticdir = staticdir self.unconstrained_file_access = unconstrained_file_access self.request_host = request_host - self.websocket_key = websocket_key - self.is_client = is_client + self.websocket_key = websocket_key # TODO: refactor this into the protocol + self.protocol = protocol Sep = pp.Optional(pp.Literal(":")).suppress() diff --git a/libpathod/language/http2.py b/libpathod/language/http2.py new file mode 100644 index 00000000..d78fc5c8 --- /dev/null +++ b/libpathod/language/http2.py @@ -0,0 +1,119 @@ +import os +import netlib.http2 +import pyparsing as pp +from . import base, generators, actions, message + +""" + Normal HTTP requests: + <method>:<path>:<header>:<body> + e.g.: + GET:/ + GET:/:foo=bar + POST:/:foo=bar:'content body payload' + + Individual HTTP/2 frames: + h2f:<payload_length>:<type>:<flags>:<stream_id>:<payload> + e.g.: + h2f:0:PING + h2f:42:HEADERS:END_HEADERS:0x1234567:foo=bar,host=example.com + h2f:42:DATA:END_STREAM,PADDED:0x1234567:'content body payload' +""" + + +class Method(base.OptionsOrValue): + options = [ + "GET", + "HEAD", + "POST", + "PUT", + "DELETE", + ] + + +class Path(base.Value): + pass + + +class Header(base.KeyValue): + preamble = "h" + + +class Body(base.Value): + preamble = "b" + + +class Times(base.Integer): + preamble = "x" + + +class Request(message.Message): + comps = ( + Header, + Body, + + Times, + ) + + @property + def method(self): + return self.tok(Method) + + @property + def path(self): + return self.tok(Path) + + @property + def headers(self): + return self.toks(Header) + + @property + def body(self): + return self.tok(Body) + + @property + def times(self): + return self.tok(Times) + + @property + def actions(self): + return [] + + @classmethod + def expr(klass): + parts = [i.expr() for i in klass.comps] + atom = pp.MatchFirst(parts) + resp = pp.And( + [ + Method.expr(), + base.Sep, + Path.expr(), + base.Sep, + pp.ZeroOrMore(base.Sep + atom) + ] + ) + resp = resp.setParseAction(klass) + return resp + + def resolve(self, settings, msg=None): + tokens = self.tokens[:] + return self.__class__( + [i.resolve(settings, self) for i in tokens] + ) + + def values(self, settings): + return settings.protocol.create_request( + self.method.value.get_generator(settings), + self.path, + self.headers, + self.body) + + def spec(self): + return ":".join([i.spec() for i in self.tokens]) + + +# class H2F(base.CaselessLiteral): +# TOK = "h2f" +# +# +# class WebsocketFrame(message.Message): +# pass |