mitmproxy/libpathod/language/http2.py

215 lines
4.5 KiB
Python
Raw Normal View History

2015-06-08 08:45:17 +00:00
import pyparsing as pp
2015-06-18 16:05:09 +00:00
from . import base, message
2015-06-08 08:45:17 +00:00
"""
Normal HTTP requests:
<method>:<path>:<header>:<body>
e.g.:
GET:/
2015-06-18 09:07:33 +00:00
GET:/:h"foo"="bar"
POST:/:h"foo"="bar":b'content body payload'
Normal HTTP responses:
<code>:<header>:<body>
e.g.:
200
302:h"foo"="bar"
404:h"foo"="bar":b'content body payload'
2015-06-08 08:45:17 +00:00
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):
unique_name = None
2015-06-08 08:45:17 +00:00
preamble = "h"
def values(self, settings):
return (
self.key.get_generator(settings),
self.value.get_generator(settings),
)
2015-06-08 08:45:17 +00:00
class Body(base.Value):
preamble = "b"
class Times(base.Integer):
preamble = "x"
2015-06-11 14:13:22 +00:00
class Code(base.Integer):
pass
2015-06-08 08:45:17 +00:00
2015-06-08 08:45:17 +00:00
class Request(message.Message):
comps = (
Header,
Body,
Times,
)
2015-06-11 14:13:22 +00:00
logattrs = ["method", "path"]
def __init__(self, tokens):
super(Request, self).__init__(tokens)
2015-06-11 14:13:22 +00:00
self.rendered_values = None
2015-06-08 08:45:17 +00:00
@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
2015-06-18 09:07:33 +00:00
def expr(cls):
parts = [i.expr() for i in cls.comps]
2015-06-08 08:45:17 +00:00
atom = pp.MatchFirst(parts)
resp = pp.And(
[
Method.expr(),
base.Sep,
Path.expr(),
pp.ZeroOrMore(base.Sep + atom)
]
)
2015-06-18 09:07:33 +00:00
resp = resp.setParseAction(cls)
2015-06-08 08:45:17 +00:00
return resp
def resolve(self, settings, msg=None):
2015-06-11 14:13:22 +00:00
return self
def values(self, settings):
if self.rendered_values:
return self.rendered_values
else:
headers = [header.values(settings) for header in self.headers]
2015-06-11 14:13:22 +00:00
body = self.body
if body:
body = body.string()
self.rendered_values = settings.protocol.create_request(
self.method.string(),
self.path.string(),
headers, # TODO: parse that into a dict?!
body)
return self.rendered_values
def spec(self):
return ":".join([i.spec() for i in self.tokens])
class Response(message.Message):
unique_name = None
comps = (
Header,
Body,
)
def __init__(self, tokens):
super(Response, self).__init__(tokens)
self.rendered_values = None
self.stream_id = 0
@property
def code(self):
return self.tok(Code)
@property
def headers(self):
return self.toks(Header)
@property
def body(self):
return self.tok(Body)
@property
def actions(self):
return []
def resolve(self, settings, msg=None):
return self
@classmethod
2015-06-18 09:07:33 +00:00
def expr(cls):
parts = [i.expr() for i in cls.comps]
2015-06-11 14:13:22 +00:00
atom = pp.MatchFirst(parts)
resp = pp.And(
[
Code.expr(),
pp.ZeroOrMore(base.Sep + atom)
]
2015-06-08 08:45:17 +00:00
)
2015-06-18 09:07:33 +00:00
resp = resp.setParseAction(cls)
2015-06-11 14:13:22 +00:00
return resp
2015-06-08 08:45:17 +00:00
def values(self, settings):
2015-06-11 14:13:22 +00:00
if self.rendered_values:
return self.rendered_values
else:
headers = [header.values(settings) for header in self.headers]
2015-06-11 14:13:22 +00:00
body = self.body
if body:
2015-06-16 09:33:10 +00:00
body = body.string()
2015-06-11 14:13:22 +00:00
self.rendered_values = settings.protocol.create_response(
self.code.string(),
self.stream_id,
headers, # TODO: parse that into a dict?!
body)
return self.rendered_values
2015-06-08 08:45:17 +00:00
def spec(self):
return ":".join([i.spec() for i in self.tokens])
2015-06-18 09:07:33 +00:00
2015-06-11 14:13:22 +00:00
def make_error_response(reason, body=None):
2015-06-16 09:33:10 +00:00
tokens = [
Code("800"),
Body(base.TokValueLiteral("pathod error: " + (body or reason))),
]
return Response(tokens)
2015-06-08 08:45:17 +00:00
2015-06-18 09:07:33 +00:00
2015-06-08 13:28:24 +00:00
# class Frame(message.Message):
2015-06-08 08:45:17 +00:00
# pass