2012-03-25 22:26:02 +00:00
|
|
|
import re, cStringIO
|
2012-03-23 22:21:58 +00:00
|
|
|
import urwid
|
2012-03-25 22:26:02 +00:00
|
|
|
from PIL import Image
|
|
|
|
from PIL.ExifTags import TAGS
|
2012-03-23 22:21:58 +00:00
|
|
|
import common
|
2012-03-24 01:02:41 +00:00
|
|
|
from .. import utils, encoding, flow
|
2012-03-24 21:56:45 +00:00
|
|
|
from ..contrib import jsbeautifier
|
2012-03-23 22:21:58 +00:00
|
|
|
|
2012-03-31 22:09:25 +00:00
|
|
|
VIEW_CUTOFF = 1024*20
|
2012-03-23 22:21:58 +00:00
|
|
|
|
2012-04-01 22:30:35 +00:00
|
|
|
VIEW_AUTO = 0
|
|
|
|
VIEW_JSON = 1
|
|
|
|
VIEW_XML = 2
|
|
|
|
VIEW_URLENCODED = 3
|
|
|
|
VIEW_MULTIPART = 4
|
|
|
|
VIEW_JAVASCRIPT = 5
|
|
|
|
VIEW_IMAGE = 6
|
|
|
|
VIEW_RAW = 7
|
|
|
|
VIEW_HEX = 8
|
|
|
|
|
|
|
|
VIEW_NAMES = {
|
|
|
|
VIEW_AUTO: "Auto",
|
|
|
|
VIEW_JSON: "JSON",
|
|
|
|
VIEW_XML: "XML",
|
|
|
|
VIEW_URLENCODED: "URL-encoded",
|
|
|
|
VIEW_MULTIPART: "Multipart Form",
|
|
|
|
VIEW_JAVASCRIPT: "JavaScript",
|
|
|
|
VIEW_IMAGE: "Image",
|
|
|
|
VIEW_RAW: "Raw",
|
|
|
|
VIEW_HEX: "Hex",
|
2012-03-23 22:21:58 +00:00
|
|
|
}
|
|
|
|
|
2012-04-01 22:49:57 +00:00
|
|
|
|
|
|
|
VIEW_PROMPT = (
|
|
|
|
("auto detect", "a"),
|
|
|
|
("hex", "h"),
|
|
|
|
("image", "i"),
|
|
|
|
("javascript", "j"),
|
|
|
|
("json", "s"),
|
|
|
|
("raw", "r"),
|
|
|
|
("multipart", "m"),
|
|
|
|
("urlencoded", "u"),
|
|
|
|
("xmlish", "x"),
|
|
|
|
)
|
|
|
|
|
2012-04-01 22:30:35 +00:00
|
|
|
VIEW_SHORTCUTS = {
|
|
|
|
"a": VIEW_AUTO,
|
|
|
|
"i": VIEW_IMAGE,
|
|
|
|
"j": VIEW_JAVASCRIPT,
|
|
|
|
"s": VIEW_JSON,
|
|
|
|
"u": VIEW_URLENCODED,
|
2012-04-01 22:49:57 +00:00
|
|
|
"m": VIEW_MULTIPART,
|
2012-04-01 22:30:35 +00:00
|
|
|
"x": VIEW_XML,
|
|
|
|
"r": VIEW_RAW,
|
|
|
|
"h": VIEW_HEX,
|
2012-03-23 22:21:58 +00:00
|
|
|
}
|
|
|
|
|
2012-03-24 01:02:41 +00:00
|
|
|
CONTENT_TYPES_MAP = {
|
2012-04-01 22:30:35 +00:00
|
|
|
"text/html": VIEW_XML,
|
|
|
|
"application/json": VIEW_JSON,
|
|
|
|
"text/xml": VIEW_XML,
|
|
|
|
"multipart/form-data": VIEW_MULTIPART,
|
|
|
|
"application/x-www-form-urlencoded": VIEW_URLENCODED,
|
|
|
|
"application/x-javascript": VIEW_JAVASCRIPT,
|
|
|
|
"application/javascript": VIEW_JAVASCRIPT,
|
|
|
|
"text/javascript": VIEW_JAVASCRIPT,
|
|
|
|
"image/png": VIEW_IMAGE,
|
|
|
|
"image/jpeg": VIEW_IMAGE,
|
|
|
|
"image/gif": VIEW_IMAGE,
|
|
|
|
"image/vnd.microsoft.icon": VIEW_IMAGE,
|
|
|
|
"image/x-icon": VIEW_IMAGE,
|
2012-03-23 22:21:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
def trailer(clen, txt):
|
|
|
|
rem = clen - VIEW_CUTOFF
|
|
|
|
if rem > 0:
|
|
|
|
txt.append(urwid.Text(""))
|
|
|
|
txt.append(
|
|
|
|
urwid.Text(
|
|
|
|
[
|
|
|
|
("highlight", "... %s of data not shown"%utils.pretty_size(rem))
|
|
|
|
]
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
2012-03-24 01:02:41 +00:00
|
|
|
|
2012-03-31 22:09:25 +00:00
|
|
|
def _view_text(content, total):
|
2012-03-24 21:56:45 +00:00
|
|
|
"""
|
|
|
|
Generates a body for a chunk of text.
|
|
|
|
"""
|
2012-03-23 22:21:58 +00:00
|
|
|
txt = []
|
2012-03-31 22:09:25 +00:00
|
|
|
for i in utils.cleanBin(content).splitlines():
|
2012-03-23 22:21:58 +00:00
|
|
|
txt.append(
|
|
|
|
urwid.Text(("text", i))
|
|
|
|
)
|
2012-03-31 22:09:25 +00:00
|
|
|
trailer(total, txt)
|
2012-03-24 21:56:45 +00:00
|
|
|
return txt
|
|
|
|
|
|
|
|
|
|
|
|
def view_raw(hdrs, content):
|
2012-03-31 22:09:25 +00:00
|
|
|
txt = _view_text(content[:VIEW_CUTOFF], len(content))
|
2012-03-24 01:02:41 +00:00
|
|
|
return "Raw", txt
|
|
|
|
|
2012-03-23 22:21:58 +00:00
|
|
|
|
2012-03-24 01:02:41 +00:00
|
|
|
def view_hex(hdrs, content):
|
2012-03-23 22:21:58 +00:00
|
|
|
txt = []
|
|
|
|
for offset, hexa, s in utils.hexdump(content[:VIEW_CUTOFF]):
|
|
|
|
txt.append(urwid.Text([
|
|
|
|
("offset", offset),
|
|
|
|
" ",
|
|
|
|
("text", hexa),
|
|
|
|
" ",
|
|
|
|
("text", s),
|
|
|
|
]))
|
|
|
|
trailer(len(content), txt)
|
2012-04-01 23:22:01 +00:00
|
|
|
return "Hex", txt
|
2012-03-23 22:21:58 +00:00
|
|
|
|
2012-03-24 01:02:41 +00:00
|
|
|
|
|
|
|
def view_xmlish(hdrs, content):
|
2012-03-23 22:21:58 +00:00
|
|
|
txt = []
|
|
|
|
for i in utils.pretty_xmlish(content[:VIEW_CUTOFF]):
|
|
|
|
txt.append(
|
|
|
|
urwid.Text(("text", i)),
|
|
|
|
)
|
|
|
|
trailer(len(content), txt)
|
2012-03-24 01:02:41 +00:00
|
|
|
return "XML-like data", txt
|
|
|
|
|
|
|
|
|
|
|
|
def view_json(hdrs, content):
|
|
|
|
lines = utils.pretty_json(content)
|
|
|
|
if lines:
|
|
|
|
txt = []
|
|
|
|
sofar = 0
|
|
|
|
for i in lines:
|
|
|
|
sofar += len(i)
|
|
|
|
txt.append(
|
|
|
|
urwid.Text(("text", i)),
|
|
|
|
)
|
|
|
|
if sofar > VIEW_CUTOFF:
|
|
|
|
break
|
|
|
|
trailer(sum(len(i) for i in lines), txt)
|
|
|
|
return "JSON", txt
|
2012-03-23 22:21:58 +00:00
|
|
|
|
|
|
|
|
2012-03-24 21:10:48 +00:00
|
|
|
def view_multipart(hdrs, content):
|
|
|
|
v = hdrs.get("content-type")
|
|
|
|
if v:
|
|
|
|
v = utils.parse_content_type(v[0])
|
|
|
|
if not v:
|
|
|
|
return
|
|
|
|
boundary = v[2].get("boundary")
|
|
|
|
if not boundary:
|
|
|
|
return
|
|
|
|
|
|
|
|
rx = re.compile(r'\bname="([^"]+)"')
|
|
|
|
keys = []
|
|
|
|
vals = []
|
|
|
|
|
|
|
|
for i in content.split("--" + boundary):
|
|
|
|
parts = i.splitlines()
|
|
|
|
if len(parts) > 1 and parts[0][0:2] != "--":
|
|
|
|
match = rx.search(parts[1])
|
|
|
|
if match:
|
|
|
|
keys.append(match.group(1) + ":")
|
|
|
|
vals.append(utils.cleanBin(
|
|
|
|
"\n".join(parts[3+parts[2:].index(""):])
|
|
|
|
))
|
|
|
|
r = [
|
|
|
|
urwid.Text(("highlight", "Form data:\n")),
|
|
|
|
]
|
|
|
|
r.extend(common.format_keyvals(
|
|
|
|
zip(keys, vals),
|
|
|
|
key = "header",
|
|
|
|
val = "text"
|
|
|
|
))
|
|
|
|
return "Multipart form", r
|
2012-03-23 22:21:58 +00:00
|
|
|
|
|
|
|
|
2012-03-24 01:02:41 +00:00
|
|
|
def view_urlencoded(hdrs, content):
|
|
|
|
lines = utils.urldecode(content)
|
|
|
|
if lines:
|
|
|
|
body = common.format_keyvals(
|
|
|
|
[(k+":", v) for (k, v) in lines],
|
|
|
|
key = "header",
|
|
|
|
val = "text"
|
|
|
|
)
|
|
|
|
return "URLEncoded form", body
|
2012-03-23 22:21:58 +00:00
|
|
|
|
|
|
|
|
2012-03-24 21:56:45 +00:00
|
|
|
def view_javascript(hdrs, content):
|
|
|
|
opts = jsbeautifier.default_options()
|
|
|
|
opts.indent_size = 2
|
2012-03-31 22:09:25 +00:00
|
|
|
res = jsbeautifier.beautify(content[:VIEW_CUTOFF], opts)
|
|
|
|
return "JavaScript", _view_text(res, len(content))
|
2012-03-24 21:56:45 +00:00
|
|
|
|
|
|
|
|
2012-03-25 22:26:02 +00:00
|
|
|
def view_image(hdrs, content):
|
|
|
|
try:
|
|
|
|
img = Image.open(cStringIO.StringIO(content))
|
|
|
|
except IOError:
|
|
|
|
return None
|
|
|
|
parts = [
|
|
|
|
("Format", str(img.format_description)),
|
|
|
|
("Size", "%s x %s px"%img.size),
|
|
|
|
("Mode", str(img.mode)),
|
|
|
|
]
|
|
|
|
for i in sorted(img.info.keys()):
|
|
|
|
if i != "exif":
|
|
|
|
parts.append(
|
|
|
|
(str(i), str(img.info[i]))
|
|
|
|
)
|
|
|
|
if hasattr(img, "_getexif"):
|
|
|
|
ex = img._getexif()
|
|
|
|
if ex:
|
|
|
|
for i in sorted(ex.keys()):
|
|
|
|
tag = TAGS.get(i, i)
|
|
|
|
parts.append(
|
|
|
|
(str(tag), str(ex[i]))
|
|
|
|
)
|
|
|
|
clean = []
|
|
|
|
for i in parts:
|
|
|
|
clean.append([utils.cleanBin(i[0]), utils.cleanBin(i[1])])
|
|
|
|
fmt = common.format_keyvals(
|
|
|
|
clean,
|
|
|
|
key = "header",
|
|
|
|
val = "text"
|
|
|
|
)
|
|
|
|
return "%s image"%img.format, fmt
|
|
|
|
|
|
|
|
|
2012-03-24 01:02:41 +00:00
|
|
|
PRETTY_FUNCTION_MAP = {
|
2012-04-01 22:30:35 +00:00
|
|
|
VIEW_XML: view_xmlish,
|
|
|
|
VIEW_JSON: view_json,
|
|
|
|
VIEW_URLENCODED: view_urlencoded,
|
|
|
|
VIEW_MULTIPART: view_multipart,
|
|
|
|
VIEW_JAVASCRIPT: view_javascript,
|
|
|
|
VIEW_IMAGE: view_image,
|
|
|
|
VIEW_HEX: view_hex,
|
|
|
|
VIEW_RAW: view_raw,
|
2012-03-24 01:02:41 +00:00
|
|
|
}
|
2012-03-23 22:21:58 +00:00
|
|
|
|
2012-04-01 22:30:35 +00:00
|
|
|
def get_view_func(viewmode, hdrs, content):
|
2012-03-23 22:21:58 +00:00
|
|
|
"""
|
2012-03-24 01:02:41 +00:00
|
|
|
Returns a function object.
|
2012-03-23 22:21:58 +00:00
|
|
|
"""
|
2012-04-01 22:30:35 +00:00
|
|
|
if viewmode == VIEW_AUTO:
|
|
|
|
ctype = hdrs.get("content-type")
|
|
|
|
if ctype:
|
|
|
|
ctype = ctype[0]
|
|
|
|
ct = utils.parse_content_type(ctype) if ctype else None
|
|
|
|
if ct:
|
|
|
|
viewmode = CONTENT_TYPES_MAP.get("%s/%s"%(ct[0], ct[1]))
|
|
|
|
if not viewmode and utils.isXML(content):
|
|
|
|
viewmode = VIEW_XML
|
|
|
|
return PRETTY_FUNCTION_MAP.get(viewmode, view_raw)
|
|
|
|
|
|
|
|
|
|
|
|
def get_content_view(viewmode, hdrItems, content):
|
2012-03-24 01:02:41 +00:00
|
|
|
"""
|
|
|
|
Returns a (msg, body) tuple.
|
|
|
|
"""
|
|
|
|
msg = []
|
|
|
|
|
|
|
|
hdrs = flow.ODictCaseless([list(i) for i in hdrItems])
|
|
|
|
|
|
|
|
enc = hdrs.get("content-encoding")
|
|
|
|
if enc and enc[0] != "identity":
|
|
|
|
decoded = encoding.decode(enc[0], content)
|
|
|
|
if decoded:
|
|
|
|
content = decoded
|
|
|
|
msg.append("[decoded %s]"%enc[0])
|
2012-04-01 22:30:35 +00:00
|
|
|
func = get_view_func(viewmode, hdrs, content)
|
2012-03-24 01:02:41 +00:00
|
|
|
ret = func(hdrs, content)
|
|
|
|
if not ret:
|
2012-04-01 23:22:01 +00:00
|
|
|
viewmode = VIEW_RAW
|
2012-03-24 01:02:41 +00:00
|
|
|
ret = view_raw(hdrs, content)
|
2012-04-01 23:22:01 +00:00
|
|
|
msg.append("Fallback to Raw")
|
|
|
|
else:
|
|
|
|
msg.append(ret[0])
|
2012-03-24 01:02:41 +00:00
|
|
|
return " ".join(msg), ret[1]
|