aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSahn Lam <sahn@pobox.com>2012-08-16 23:27:47 -0700
committerSahn Lam <sahn@pobox.com>2012-08-17 18:45:26 -0700
commit3189d144a521fcc98695dd079fb3dd4304de2eee (patch)
treef0d8198a5e1094be6ecf7cefe96aac95b26ea778
parenta66d018363e6d0c597577ed459308d4c80cbc2cc (diff)
downloadmitmproxy-3189d144a521fcc98695dd079fb3dd4304de2eee.tar.gz
mitmproxy-3189d144a521fcc98695dd079fb3dd4304de2eee.tar.bz2
mitmproxy-3189d144a521fcc98695dd079fb3dd4304de2eee.zip
Optional AMF decoding support
If PyAMF is installed, enable AMF decoding.
-rw-r--r--libmproxy/console/contentview.py28
-rw-r--r--libmproxy/console/help.py4
-rw-r--r--libmproxy/utils.py36
-rw-r--r--test/data/test.amfbin0 -> 432 bytes
-rw-r--r--test/test_console_contentview.py23
5 files changed, 89 insertions, 2 deletions
diff --git a/libmproxy/console/contentview.py b/libmproxy/console/contentview.py
index 2443c188..4efbb2b1 100644
--- a/libmproxy/console/contentview.py
+++ b/libmproxy/console/contentview.py
@@ -20,6 +20,7 @@ VIEW_RAW = 7
VIEW_HEX = 8
VIEW_HTML = 9
VIEW_OUTLINE = 10
+VIEW_AMF = 11
VIEW_NAMES = {
VIEW_AUTO: "Auto",
@@ -36,7 +37,7 @@ VIEW_NAMES = {
}
-VIEW_PROMPT = (
+VIEW_PROMPT = [
("auto detect", "a"),
("hex", "e"),
("html", "h"),
@@ -48,7 +49,7 @@ VIEW_PROMPT = (
("multipart", "m"),
("urlencoded", "u"),
("xml", "x"),
-)
+]
VIEW_SHORTCUTS = {
"a": VIEW_AUTO,
@@ -285,6 +286,10 @@ def view_image(hdrs, content, limit):
)
return "%s image"%img.format, fmt
+def view_amf(hdrs, content, limit):
+ s = utils.pretty_amf(content)
+ if s:
+ return "AMF", _view_text(s[:limit], len(s), limit)
PRETTY_FUNCTION_MAP = {
VIEW_XML: view_xml,
@@ -344,3 +349,22 @@ def get_content_view(viewmode, hdrItems, content, limit):
else:
msg.append(ret[0])
return " ".join(msg), ret[1]
+
+
+#
+# Enable optional decoding methods at runtime
+#
+
+# AMF decoding requires pyamf
+try:
+ import pyamf
+
+ VIEW_SHORTCUTS["f"] = VIEW_AMF
+ VIEW_PROMPT.append(("amf", "f"))
+ VIEW_NAMES[VIEW_AMF] = "AMF"
+ CONTENT_TYPES_MAP["application/x-amf"] = VIEW_AMF
+ PRETTY_FUNCTION_MAP[VIEW_AMF] = view_amf
+except ImportError:
+ pass
+
+
diff --git a/libmproxy/console/help.py b/libmproxy/console/help.py
index 64428fcc..e278e763 100644
--- a/libmproxy/console/help.py
+++ b/libmproxy/console/help.py
@@ -83,6 +83,10 @@ class HelpView(urwid.ListBox):
common.highlight_key("xml", "x") +
[("text", ": XML")]
),
+ (None,
+ common.highlight_key("amf", "f") +
+ [("text", ": AMF (requires PyAMF)")]
+ ),
("o", "toggle options:"),
(None,
common.highlight_key("anticache", "a") +
diff --git a/libmproxy/utils.py b/libmproxy/utils.py
index 871beb35..a89419a9 100644
--- a/libmproxy/utils.py
+++ b/libmproxy/utils.py
@@ -81,6 +81,42 @@ def pretty_json(s):
return json.dumps(p, sort_keys=True, indent=4).split("\n")
+def pretty_amf(s):
+ """
+ Takes an AMF encoded string, decodes it and returns a nicely indented
+ string in JSON format.
+
+ Reqires pyamf module. The function returns None if pyamf is not
+ installed.
+ """
+ try:
+ import pyamf
+ from pyamf import remoting
+ except ImportError:
+ return None
+
+ envelope = remoting.decode(s)
+ if not envelope:
+ return None
+
+ data = {}
+ data['amfVersion'] = envelope.amfVersion
+ for target, message in iter(envelope):
+
+ one_message = {}
+
+ if hasattr(message, 'status'):
+ one_message['status'] = message.status
+
+ if hasattr(message, 'target'):
+ one_message['target'] = message.target
+
+ one_message['body'] = message.body
+ data[target] = one_message
+
+ return json.dumps(data, indent=4)
+
+
def urldecode(s):
"""
Takes a urlencoded string and returns a list of (key, value) tuples.
diff --git a/test/data/test.amf b/test/data/test.amf
new file mode 100644
index 00000000..c8fc261d
--- /dev/null
+++ b/test/data/test.amf
Binary files differ
diff --git a/test/test_console_contentview.py b/test/test_console_contentview.py
index fbb7e6d2..6f3958df 100644
--- a/test/test_console_contentview.py
+++ b/test/test_console_contentview.py
@@ -53,6 +53,20 @@ class TestContentView:
)
assert f is cv.view_xml
+ try:
+ import pyamf
+
+ f = cv.get_view_func(
+ cv.VIEW_AUTO,
+ flow.ODictCaseless(
+ [["content-type", "application/x-amf"]],
+ ),
+ ""
+ )
+ assert f is cv.view_amf
+ except ImportError:
+ pass
+
def test_view_urlencoded(self):
d = utils.urlencode([("one", "two"), ("three", "four")])
assert cv.view_urlencoded([], d, 100)
@@ -111,6 +125,15 @@ class TestContentView:
assert not cv.view_image([], "flibble", sys.maxint)
+ def test_view_amf(self):
+ try:
+ import pyamf
+
+ p = tutils.test_data.path("data/test.amf")
+ assert cv.view_amf([], file(p).read(), sys.maxint)
+ except ImportError:
+ pass
+
def test_view_multipart(self):
v = """
--AaB03x