aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAldo Cortesi <aldo@nullcube.com>2012-06-24 17:47:55 +1200
committerAldo Cortesi <aldo@nullcube.com>2012-06-24 17:47:55 +1200
commitf8622ea914b506013625c539388349d53b4a7e58 (patch)
treec79d233fb8ce6c17224f80f9086a7c3e4ef3d796
parent75f06d56cd87c9458a758277bdc1905d0637a532 (diff)
downloadmitmproxy-f8622ea914b506013625c539388349d53b4a7e58.tar.gz
mitmproxy-f8622ea914b506013625c539388349d53b4a7e58.tar.bz2
mitmproxy-f8622ea914b506013625c539388349d53b4a7e58.zip
Simple request spec parsing.
-rw-r--r--libpathod/rparse.py58
-rw-r--r--libpathod/utils.py9
-rw-r--r--test/test_rparse.py10
3 files changed, 67 insertions, 10 deletions
diff --git a/libpathod/rparse.py b/libpathod/rparse.py
index 3824406d..50ae9804 100644
--- a/libpathod/rparse.py
+++ b/libpathod/rparse.py
@@ -1,6 +1,7 @@
import operator, string, random, mmap, os, time
import contrib.pyparsing as pp
from netlib import http_status
+import utils
BLOCKSIZE = 1024
@@ -305,7 +306,7 @@ class Method:
# it to be canonical. The user can specify a different case by using a
# string value literal.
if isinstance(value, basestring):
- value = value.upper()
+ value = ValueLiteral(value.upper())
self.value = value
def accept(self, settings, r):
@@ -406,6 +407,46 @@ class Code:
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:
comps = (
Body,
@@ -423,12 +464,6 @@ class Response:
self.headers = []
self.actions = []
- def get_header(self, hdr):
- for k, v in self.headers:
- if k[:len(hdr)].lower() == hdr:
- return v
- return None
-
@classmethod
def expr(klass):
parts = [i.expr() for i in klass.comps]
@@ -454,7 +489,7 @@ class Response:
def serve(self, fp):
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(
(
LiteralGenerator("Content-Length"),
@@ -540,3 +575,10 @@ def parse_response(settings, s):
return CraftedResponse(settings, s, Response.expr().parseString(s, parseAll=True))
except pp.ParseException, v:
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)
diff --git a/libpathod/utils.py b/libpathod/utils.py
index 39732849..c656a0d0 100644
--- a/libpathod/utils.py
+++ b/libpathod/utils.py
@@ -1,6 +1,15 @@
import os, re
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):
"""
diff --git a/test/test_rparse.py b/test/test_rparse.py
index 2b8543a2..2a76c3e8 100644
--- a/test/test_rparse.py
+++ b/test/test_rparse.py
@@ -188,7 +188,13 @@ class TestPauses:
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):
tutils.raises(rparse.ParseException, rparse.parse_response, {}, "400:msg,b:")
try:
@@ -199,7 +205,7 @@ class TestParse:
def test_parse_header(self):
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):
r = rparse.parse_response({}, "400:p10,0")