aboutsummaryrefslogtreecommitdiffstats
path: root/libpathod/language
diff options
context:
space:
mode:
authorAldo Cortesi <aldo@nullcube.com>2015-06-08 23:06:09 +1200
committerAldo Cortesi <aldo@nullcube.com>2015-06-08 23:06:09 +1200
commit05efcf0a786b0bc51257b322014fceb6561d0f48 (patch)
treec316aec35670bb43f28eb9d3373564dbdb9614a2 /libpathod/language
parent7b4e50bb6868b7e0c63137c636720ccd3b974faa (diff)
parent293e3c68969f6abdc09cc390f93b658e60ce79be (diff)
downloadmitmproxy-05efcf0a786b0bc51257b322014fceb6561d0f48.tar.gz
mitmproxy-05efcf0a786b0bc51257b322014fceb6561d0f48.tar.bz2
mitmproxy-05efcf0a786b0bc51257b322014fceb6561d0f48.zip
Merge pull request #25 from Kriechi/pathoc-http2
[WIP] pathoc: HTTP/2
Diffstat (limited to 'libpathod/language')
-rw-r--r--libpathod/language/__init__.py24
-rw-r--r--libpathod/language/base.py8
-rw-r--r--libpathod/language/http2.py119
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