mirror of
https://github.com/Grasscutters/mitmproxy.git
synced 2024-11-23 08:11:00 +00:00
Simple request spec parsing.
This commit is contained in:
parent
75f06d56cd
commit
f8622ea914
@ -1,6 +1,7 @@
|
|||||||
import operator, string, random, mmap, os, time
|
import operator, string, random, mmap, os, time
|
||||||
import contrib.pyparsing as pp
|
import contrib.pyparsing as pp
|
||||||
from netlib import http_status
|
from netlib import http_status
|
||||||
|
import utils
|
||||||
|
|
||||||
BLOCKSIZE = 1024
|
BLOCKSIZE = 1024
|
||||||
|
|
||||||
@ -305,7 +306,7 @@ class Method:
|
|||||||
# it to be canonical. The user can specify a different case by using a
|
# it to be canonical. The user can specify a different case by using a
|
||||||
# string value literal.
|
# string value literal.
|
||||||
if isinstance(value, basestring):
|
if isinstance(value, basestring):
|
||||||
value = value.upper()
|
value = ValueLiteral(value.upper())
|
||||||
self.value = value
|
self.value = value
|
||||||
|
|
||||||
def accept(self, settings, r):
|
def accept(self, settings, r):
|
||||||
@ -406,6 +407,46 @@ class Code:
|
|||||||
return e.setParseAction(lambda x: klass(*x))
|
return e.setParseAction(lambda x: klass(*x))
|
||||||
|
|
||||||
|
|
||||||
|
class Request:
|
||||||
|
comps = (
|
||||||
|
Body,
|
||||||
|
Header,
|
||||||
|
PauseAt,
|
||||||
|
DisconnectAt,
|
||||||
|
ShortcutContentType,
|
||||||
|
)
|
||||||
|
version = "HTTP/1.1"
|
||||||
|
body = LiteralGenerator("")
|
||||||
|
def __init__(self):
|
||||||
|
self.headers = []
|
||||||
|
self.actions = []
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def expr(klass):
|
||||||
|
parts = [i.expr() for i in klass.comps]
|
||||||
|
atom = pp.MatchFirst(parts)
|
||||||
|
resp = pp.And(
|
||||||
|
[
|
||||||
|
Method.expr(),
|
||||||
|
pp.ZeroOrMore(pp.Literal(":").suppress() + atom)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
return resp
|
||||||
|
|
||||||
|
|
||||||
|
class CraftedRequest(Request):
|
||||||
|
def __init__(self, settings, spec, tokens):
|
||||||
|
Request.__init__(self)
|
||||||
|
self.spec, self.tokens = spec, tokens
|
||||||
|
for i in tokens:
|
||||||
|
i.accept(settings, self)
|
||||||
|
|
||||||
|
def serve(self, fp):
|
||||||
|
d = Request.serve(self, fp)
|
||||||
|
d["spec"] = self.spec
|
||||||
|
return d
|
||||||
|
|
||||||
|
|
||||||
class Response:
|
class Response:
|
||||||
comps = (
|
comps = (
|
||||||
Body,
|
Body,
|
||||||
@ -423,12 +464,6 @@ class Response:
|
|||||||
self.headers = []
|
self.headers = []
|
||||||
self.actions = []
|
self.actions = []
|
||||||
|
|
||||||
def get_header(self, hdr):
|
|
||||||
for k, v in self.headers:
|
|
||||||
if k[:len(hdr)].lower() == hdr:
|
|
||||||
return v
|
|
||||||
return None
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def expr(klass):
|
def expr(klass):
|
||||||
parts = [i.expr() for i in klass.comps]
|
parts = [i.expr() for i in klass.comps]
|
||||||
@ -454,7 +489,7 @@ class Response:
|
|||||||
|
|
||||||
def serve(self, fp):
|
def serve(self, fp):
|
||||||
started = time.time()
|
started = time.time()
|
||||||
if self.body and not self.get_header("Content-Length"):
|
if self.body and not utils.get_header("Content-Length", self.headers):
|
||||||
self.headers.append(
|
self.headers.append(
|
||||||
(
|
(
|
||||||
LiteralGenerator("Content-Length"),
|
LiteralGenerator("Content-Length"),
|
||||||
@ -540,3 +575,10 @@ def parse_response(settings, s):
|
|||||||
return CraftedResponse(settings, s, Response.expr().parseString(s, parseAll=True))
|
return CraftedResponse(settings, s, Response.expr().parseString(s, parseAll=True))
|
||||||
except pp.ParseException, v:
|
except pp.ParseException, v:
|
||||||
raise ParseException(v.msg, v.line, v.col)
|
raise ParseException(v.msg, v.line, v.col)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_request(settings, s):
|
||||||
|
try:
|
||||||
|
return CraftedRequest(settings, s, Request.expr().parseString(s, parseAll=True))
|
||||||
|
except pp.ParseException, v:
|
||||||
|
raise ParseException(v.msg, v.line, v.col)
|
||||||
|
@ -1,6 +1,15 @@
|
|||||||
import os, re
|
import os, re
|
||||||
import rparse
|
import rparse
|
||||||
|
|
||||||
|
def get_header(val, headers):
|
||||||
|
"""
|
||||||
|
Header keys may be Values, so we have to "generate" them as we try the match.
|
||||||
|
"""
|
||||||
|
for k, v in headers:
|
||||||
|
if len(k) == len(val) and k[:].lower() == val:
|
||||||
|
return v
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def parse_anchor_spec(s):
|
def parse_anchor_spec(s):
|
||||||
"""
|
"""
|
||||||
|
@ -188,7 +188,13 @@ class TestPauses:
|
|||||||
assert r.actions[0] == (10, "pause", 10)
|
assert r.actions[0] == (10, "pause", 10)
|
||||||
|
|
||||||
|
|
||||||
class TestParse:
|
class TestParseRequest:
|
||||||
|
def test_simple(self):
|
||||||
|
r = rparse.parse_request({}, "GET")
|
||||||
|
assert r.method == "GET"
|
||||||
|
|
||||||
|
|
||||||
|
class TestParseResponse:
|
||||||
def test_parse_err(self):
|
def test_parse_err(self):
|
||||||
tutils.raises(rparse.ParseException, rparse.parse_response, {}, "400:msg,b:")
|
tutils.raises(rparse.ParseException, rparse.parse_response, {}, "400:msg,b:")
|
||||||
try:
|
try:
|
||||||
@ -199,7 +205,7 @@ class TestParse:
|
|||||||
|
|
||||||
def test_parse_header(self):
|
def test_parse_header(self):
|
||||||
r = rparse.parse_response({}, '400:h"foo"="bar"')
|
r = rparse.parse_response({}, '400:h"foo"="bar"')
|
||||||
assert r.get_header("foo") == "bar"
|
assert utils.get_header("foo", r.headers)
|
||||||
|
|
||||||
def test_parse_pause_before(self):
|
def test_parse_pause_before(self):
|
||||||
r = rparse.parse_response({}, "400:p10,0")
|
r = rparse.parse_response({}, "400:p10,0")
|
||||||
|
Loading…
Reference in New Issue
Block a user