mirror of
https://github.com/mitmproxy/mitmproxy.git
synced 2024-12-04 19:46:44 +00:00
Huge cleanup of content viewers.
This commit is contained in:
parent
5c80450ce7
commit
11c63dcb9f
@ -159,10 +159,10 @@ class StatusBar(common.WWrap):
|
||||
r.append("[")
|
||||
r.append(("heading_key", "P"))
|
||||
r.append(":%s]"%utils.unparse_url(*self.master.server.config.reverse_proxy))
|
||||
if self.master.state.default_body_view != contentview.VIEW_AUTO:
|
||||
if self.master.state.default_body_view.name != "Auto":
|
||||
r.append("[")
|
||||
r.append(("heading_key", "M"))
|
||||
r.append(":%s]"%contentview.VIEW_NAMES[self.master.state.default_body_view])
|
||||
r.append(":%s]"%self.master.state.default_body_view.name)
|
||||
|
||||
opts = []
|
||||
if self.master.anticache:
|
||||
@ -255,7 +255,7 @@ class ConsoleState(flow.State):
|
||||
flow.State.__init__(self)
|
||||
self.focus = None
|
||||
self.follow_focus = None
|
||||
self.default_body_view = contentview.VIEW_AUTO
|
||||
self.default_body_view = contentview.ViewAuto
|
||||
self.view_flow_mode = common.VIEW_FLOW_REQUEST
|
||||
self.last_script = ""
|
||||
self.last_saveload = ""
|
||||
@ -736,7 +736,7 @@ class ConsoleMaster(flow.FlowMaster):
|
||||
return self.state.set_intercept(txt)
|
||||
|
||||
def change_default_display_mode(self, t):
|
||||
v = contentview.VIEW_SHORTCUTS.get(t)
|
||||
v = contentview.get_by_shortcut(t)
|
||||
self.state.default_body_view = v
|
||||
if self.currentflow:
|
||||
self.refresh_flow(self.currentflow)
|
||||
@ -835,7 +835,7 @@ class ConsoleMaster(flow.FlowMaster):
|
||||
elif k == "M":
|
||||
self.prompt_onekey(
|
||||
"Global default display mode",
|
||||
contentview.VIEW_PROMPT,
|
||||
contentview.view_prompts,
|
||||
self.change_default_display_mode
|
||||
)
|
||||
elif k == "P":
|
||||
|
@ -9,78 +9,20 @@ from ..contrib import jsbeautifier, html2text
|
||||
|
||||
VIEW_CUTOFF = 1024*50
|
||||
|
||||
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_HTML = 9
|
||||
VIEW_OUTLINE = 10
|
||||
VIEW_AMF = 11
|
||||
|
||||
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",
|
||||
VIEW_HTML: "HTML",
|
||||
VIEW_OUTLINE: "HTML Outline",
|
||||
}
|
||||
def _view_text(content, total, limit):
|
||||
"""
|
||||
Generates a body for a chunk of text.
|
||||
"""
|
||||
txt = []
|
||||
for i in utils.cleanBin(content).splitlines():
|
||||
txt.append(
|
||||
urwid.Text(("text", i), wrap="any")
|
||||
)
|
||||
trailer(total, txt, limit)
|
||||
return txt
|
||||
|
||||
|
||||
VIEW_PROMPT = [
|
||||
("auto detect", "a"),
|
||||
("hex", "e"),
|
||||
("html", "h"),
|
||||
("image", "i"),
|
||||
("javascript", "j"),
|
||||
("html outline", "o"),
|
||||
("json", "s"),
|
||||
("raw", "r"),
|
||||
("multipart", "m"),
|
||||
("urlencoded", "u"),
|
||||
("xml", "x"),
|
||||
]
|
||||
|
||||
VIEW_SHORTCUTS = {
|
||||
"a": VIEW_AUTO,
|
||||
"x": VIEW_XML,
|
||||
"h": VIEW_HTML,
|
||||
"i": VIEW_IMAGE,
|
||||
"j": VIEW_JAVASCRIPT,
|
||||
"s": VIEW_JSON,
|
||||
"u": VIEW_URLENCODED,
|
||||
"m": VIEW_MULTIPART,
|
||||
"o": VIEW_OUTLINE,
|
||||
"r": VIEW_RAW,
|
||||
"e": VIEW_HEX,
|
||||
}
|
||||
|
||||
CONTENT_TYPES_MAP = {
|
||||
"text/html": VIEW_HTML,
|
||||
"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,
|
||||
}
|
||||
|
||||
def trailer(clen, txt, limit):
|
||||
rem = clen - limit
|
||||
if rem > 0:
|
||||
@ -96,228 +38,310 @@ def trailer(clen, txt, limit):
|
||||
)
|
||||
|
||||
|
||||
def _view_text(content, total, limit):
|
||||
"""
|
||||
Generates a body for a chunk of text.
|
||||
"""
|
||||
txt = []
|
||||
for i in utils.cleanBin(content).splitlines():
|
||||
txt.append(
|
||||
urwid.Text(("text", i), wrap="any")
|
||||
)
|
||||
trailer(total, txt, limit)
|
||||
return txt
|
||||
class ViewAuto:
|
||||
name = "Auto"
|
||||
prompt = ("auto", "a")
|
||||
content_types = []
|
||||
|
||||
|
||||
def view_raw(hdrs, content, limit):
|
||||
txt = _view_text(content[:limit], len(content), limit)
|
||||
return "Raw", txt
|
||||
class ViewRaw:
|
||||
name = "Raw"
|
||||
prompt = ("raw", "r")
|
||||
content_types = []
|
||||
def __call__(self, hdrs, content, limit):
|
||||
txt = _view_text(content[:limit], len(content), limit)
|
||||
return "Raw", txt
|
||||
|
||||
|
||||
def view_hex(hdrs, content, limit):
|
||||
txt = []
|
||||
for offset, hexa, s in utils.hexdump(content[:limit]):
|
||||
txt.append(urwid.Text([
|
||||
("offset", offset),
|
||||
" ",
|
||||
("text", hexa),
|
||||
" ",
|
||||
("text", s),
|
||||
]))
|
||||
trailer(len(content), txt, limit)
|
||||
return "Hex", txt
|
||||
|
||||
|
||||
def view_xml(hdrs, content, limit):
|
||||
parser = lxml.etree.XMLParser(remove_blank_text=True, resolve_entities=False, strip_cdata=False, recover=False)
|
||||
try:
|
||||
document = lxml.etree.fromstring(content, parser)
|
||||
except lxml.etree.XMLSyntaxError:
|
||||
return None
|
||||
docinfo = document.getroottree().docinfo
|
||||
|
||||
prev = []
|
||||
p = document.getroottree().getroot().getprevious()
|
||||
while p is not None:
|
||||
prev.insert(
|
||||
0,
|
||||
lxml.etree.tostring(p)
|
||||
)
|
||||
p = p.getprevious()
|
||||
doctype=docinfo.doctype
|
||||
if prev:
|
||||
doctype += "\n".join(prev).strip()
|
||||
doctype = doctype.strip()
|
||||
|
||||
s = lxml.etree.tostring(
|
||||
document,
|
||||
pretty_print=True,
|
||||
xml_declaration=True,
|
||||
doctype=doctype or None,
|
||||
encoding = docinfo.encoding
|
||||
)
|
||||
|
||||
txt = []
|
||||
for i in s[:limit].strip().split("\n"):
|
||||
txt.append(
|
||||
urwid.Text(("text", i)),
|
||||
)
|
||||
trailer(len(content), txt, limit)
|
||||
return "XML-like data", txt
|
||||
|
||||
|
||||
def view_html(hdrs, content, limit):
|
||||
if utils.isXML(content):
|
||||
parser = lxml.etree.HTMLParser(strip_cdata=True, remove_blank_text=True)
|
||||
d = lxml.html.fromstring(content, parser=parser)
|
||||
docinfo = d.getroottree().docinfo
|
||||
s = lxml.etree.tostring(d, pretty_print=True, doctype=docinfo.doctype)
|
||||
return "HTML", _view_text(s[:limit], len(s), limit)
|
||||
|
||||
|
||||
def view_outline(hdrs, content, limit):
|
||||
content = content.decode("utf-8")
|
||||
h = html2text.HTML2Text(baseurl="")
|
||||
h.ignore_images = True
|
||||
h.body_width = 0
|
||||
content = h.handle(content)
|
||||
txt = _view_text(content[:limit], len(content), limit)
|
||||
return "HTML Outline", txt
|
||||
|
||||
|
||||
def view_json(hdrs, content, limit):
|
||||
lines = utils.pretty_json(content)
|
||||
if lines:
|
||||
class ViewHex:
|
||||
name = "Hex"
|
||||
prompt = ("hex", "e")
|
||||
content_types = []
|
||||
def __call__(self, hdrs, content, limit):
|
||||
txt = []
|
||||
sofar = 0
|
||||
for i in lines:
|
||||
sofar += len(i)
|
||||
for offset, hexa, s in utils.hexdump(content[:limit]):
|
||||
txt.append(urwid.Text([
|
||||
("offset", offset),
|
||||
" ",
|
||||
("text", hexa),
|
||||
" ",
|
||||
("text", s),
|
||||
]))
|
||||
trailer(len(content), txt, limit)
|
||||
return "Hex", txt
|
||||
|
||||
|
||||
class ViewXML:
|
||||
name = "XML"
|
||||
prompt = ("xml", "x")
|
||||
content_types = ["text/xml"]
|
||||
def __call__(self, hdrs, content, limit):
|
||||
parser = lxml.etree.XMLParser(remove_blank_text=True, resolve_entities=False, strip_cdata=False, recover=False)
|
||||
try:
|
||||
document = lxml.etree.fromstring(content, parser)
|
||||
except lxml.etree.XMLSyntaxError:
|
||||
return None
|
||||
docinfo = document.getroottree().docinfo
|
||||
|
||||
prev = []
|
||||
p = document.getroottree().getroot().getprevious()
|
||||
while p is not None:
|
||||
prev.insert(
|
||||
0,
|
||||
lxml.etree.tostring(p)
|
||||
)
|
||||
p = p.getprevious()
|
||||
doctype=docinfo.doctype
|
||||
if prev:
|
||||
doctype += "\n".join(prev).strip()
|
||||
doctype = doctype.strip()
|
||||
|
||||
s = lxml.etree.tostring(
|
||||
document,
|
||||
pretty_print=True,
|
||||
xml_declaration=True,
|
||||
doctype=doctype or None,
|
||||
encoding = docinfo.encoding
|
||||
)
|
||||
|
||||
txt = []
|
||||
for i in s[:limit].strip().split("\n"):
|
||||
txt.append(
|
||||
urwid.Text(("text", i)),
|
||||
)
|
||||
if sofar > limit:
|
||||
break
|
||||
trailer(sum(len(i) for i in lines), txt, limit)
|
||||
return "JSON", txt
|
||||
trailer(len(content), txt, limit)
|
||||
return "XML-like data", txt
|
||||
|
||||
|
||||
def view_multipart(hdrs, content, limit):
|
||||
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
|
||||
|
||||
|
||||
def view_urlencoded(hdrs, content, limit):
|
||||
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
|
||||
|
||||
|
||||
def view_javascript(hdrs, content, limit):
|
||||
opts = jsbeautifier.default_options()
|
||||
opts.indent_size = 2
|
||||
res = jsbeautifier.beautify(content[:limit], opts)
|
||||
return "JavaScript", _view_text(res, len(content), limit)
|
||||
|
||||
|
||||
def view_image(hdrs, content, limit):
|
||||
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]))
|
||||
class ViewJSON:
|
||||
name = "JSON"
|
||||
prompt = ("json", "j")
|
||||
content_types = ["application/json"]
|
||||
def __call__(self, hdrs, content, limit):
|
||||
lines = utils.pretty_json(content)
|
||||
if lines:
|
||||
txt = []
|
||||
sofar = 0
|
||||
for i in lines:
|
||||
sofar += len(i)
|
||||
txt.append(
|
||||
urwid.Text(("text", 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
|
||||
if sofar > limit:
|
||||
break
|
||||
trailer(sum(len(i) for i in lines), txt, limit)
|
||||
return "JSON", txt
|
||||
|
||||
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,
|
||||
VIEW_HTML: view_html,
|
||||
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,
|
||||
VIEW_OUTLINE: view_outline,
|
||||
}
|
||||
class ViewHTML:
|
||||
name = "HTML"
|
||||
prompt = ("html", "h")
|
||||
content_types = ["text/html"]
|
||||
def __call__(self, hdrs, content, limit):
|
||||
if utils.isXML(content):
|
||||
parser = lxml.etree.HTMLParser(strip_cdata=True, remove_blank_text=True)
|
||||
d = lxml.html.fromstring(content, parser=parser)
|
||||
docinfo = d.getroottree().docinfo
|
||||
s = lxml.etree.tostring(d, pretty_print=True, doctype=docinfo.doctype)
|
||||
return "HTML", _view_text(s[:limit], len(s), limit)
|
||||
|
||||
|
||||
class ViewHTMLOutline:
|
||||
name = "HTML Outline"
|
||||
prompt = ("html outline", "o")
|
||||
content_types = ["text/html"]
|
||||
def __call__(self, hdrs, content, limit):
|
||||
content = content.decode("utf-8")
|
||||
h = html2text.HTML2Text(baseurl="")
|
||||
h.ignore_images = True
|
||||
h.body_width = 0
|
||||
content = h.handle(content)
|
||||
txt = _view_text(content[:limit], len(content), limit)
|
||||
return "HTML Outline", txt
|
||||
|
||||
|
||||
class ViewURLEncoded:
|
||||
name = "URL-encoded"
|
||||
prompt = ("urlencoded", "u")
|
||||
content_types = ["application/x-www-form-urlencoded"]
|
||||
def __call__(self, hdrs, content, limit):
|
||||
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
|
||||
|
||||
|
||||
class ViewMultipart:
|
||||
name = "Multipart Form"
|
||||
prompt = ("multipart", "m")
|
||||
content_types = ["multipart/form-data"]
|
||||
def __call__(self, hdrs, content, limit):
|
||||
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
|
||||
|
||||
|
||||
class ViewAMF:
|
||||
name = "AMF"
|
||||
prompt = ("amf", "f")
|
||||
content_types = ["application/x-amf"]
|
||||
def __call__(self, hdrs, content, limit):
|
||||
s = utils.pretty_amf(content)
|
||||
if s:
|
||||
return "AMF", _view_text(s[:limit], len(s), limit)
|
||||
|
||||
|
||||
class ViewJavaScript:
|
||||
name = "JavaScript"
|
||||
prompt = ("javascript", "j")
|
||||
content_types = [
|
||||
"application/x-javascript",
|
||||
"application/javascript",
|
||||
"text/javascript"
|
||||
]
|
||||
def __call__(self, hdrs, content, limit):
|
||||
opts = jsbeautifier.default_options()
|
||||
opts.indent_size = 2
|
||||
res = jsbeautifier.beautify(content[:limit], opts)
|
||||
return "JavaScript", _view_text(res, len(content), limit)
|
||||
|
||||
|
||||
class ViewImage:
|
||||
name = "Image"
|
||||
prompt = ("image", "i")
|
||||
content_types = [
|
||||
"image/png",
|
||||
"image/jpeg",
|
||||
"image/gif",
|
||||
"image/vnd.microsoft.icon",
|
||||
"image/x-icon",
|
||||
]
|
||||
def __call__(self, hdrs, content, limit):
|
||||
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
|
||||
|
||||
|
||||
views = [
|
||||
ViewAuto(),
|
||||
ViewRaw(),
|
||||
ViewHex(),
|
||||
ViewJSON(),
|
||||
ViewXML(),
|
||||
ViewHTML(),
|
||||
ViewHTMLOutline(),
|
||||
ViewJavaScript(),
|
||||
ViewURLEncoded(),
|
||||
ViewMultipart(),
|
||||
ViewImage(),
|
||||
]
|
||||
try:
|
||||
import pyamf
|
||||
views.append(ViewAMF())
|
||||
except ImportError: # pragma nocover
|
||||
pass
|
||||
|
||||
|
||||
content_types_map = {}
|
||||
for i in views:
|
||||
for ct in i.content_types:
|
||||
l = content_types_map.setdefault(ct, [])
|
||||
l.append(i)
|
||||
|
||||
|
||||
view_prompts = [i.prompt for i in views]
|
||||
|
||||
|
||||
def get_by_shortcut(c):
|
||||
for i in views:
|
||||
if i.prompt[1] == c:
|
||||
return i
|
||||
|
||||
|
||||
def get(name):
|
||||
for i in views:
|
||||
if i.name == name:
|
||||
return i
|
||||
|
||||
|
||||
def get_view_func(viewmode, hdrs, content):
|
||||
"""
|
||||
Returns a function object.
|
||||
"""
|
||||
if viewmode == VIEW_AUTO:
|
||||
if viewmode.name == "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)
|
||||
ct = "%s/%s"%(ct[0], ct[1])
|
||||
if ct in content_types_map:
|
||||
return content_types_map[ct][0]
|
||||
elif utils.isXML(content):
|
||||
return ViewXML
|
||||
return ViewRaw
|
||||
else:
|
||||
return viewmode
|
||||
|
||||
|
||||
def get_content_view(viewmode, hdrItems, content, limit):
|
||||
@ -339,32 +363,14 @@ def get_content_view(viewmode, hdrItems, content, limit):
|
||||
ret = func(hdrs, content, limit)
|
||||
# Third-party viewers can fail in unexpected ways...
|
||||
except Exception, e:
|
||||
s = traceback.format_exc()
|
||||
return "", _view_text(s, len(s), len(s))
|
||||
#s = traceback.format_exc()
|
||||
#return "", _view_text(s, len(s), len(s))
|
||||
ret = None
|
||||
if not ret:
|
||||
viewmode = VIEW_RAW
|
||||
ret = view_raw(hdrs, content, limit)
|
||||
ret = get("Raw")(hdrs, content, limit)
|
||||
msg.append("Couldn't parse: falling back to Raw")
|
||||
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
|
||||
|
||||
|
||||
|
@ -180,7 +180,7 @@ class FlowView(common.WWrap):
|
||||
" ",
|
||||
('heading', "["),
|
||||
('heading_key', "m"),
|
||||
('heading', (":%s]"%contentview.VIEW_NAMES[viewmode])),
|
||||
('heading', (":%s]"%viewmode.name)),
|
||||
],
|
||||
align="right"
|
||||
)
|
||||
@ -392,7 +392,7 @@ class FlowView(common.WWrap):
|
||||
self.state.add_flow_setting(
|
||||
self.flow,
|
||||
(self.state.view_flow_mode, "prettyview"),
|
||||
contentview.VIEW_SHORTCUTS.get(t)
|
||||
contentview.get_by_shortcut(t)
|
||||
)
|
||||
self.master.refresh_flow(self.flow)
|
||||
|
||||
@ -500,7 +500,7 @@ class FlowView(common.WWrap):
|
||||
self.master.refresh_flow(self.flow)
|
||||
self.master.statusbar.message("")
|
||||
elif key == "m":
|
||||
p = list(contentview.VIEW_PROMPT)
|
||||
p = list(contentview.view_prompts)
|
||||
p.insert(0, ("clear", "c"))
|
||||
self.master.prompt_onekey(
|
||||
"Display mode",
|
||||
|
@ -92,7 +92,7 @@ def pretty_amf(s):
|
||||
try:
|
||||
import pyamf
|
||||
from pyamf import remoting
|
||||
except ImportError:
|
||||
except ImportError: # pragma nocover
|
||||
return None
|
||||
|
||||
envelope = remoting.decode(s)
|
||||
@ -102,7 +102,6 @@ def pretty_amf(s):
|
||||
data = {}
|
||||
data['amfVersion'] = envelope.amfVersion
|
||||
for target, message in iter(envelope):
|
||||
|
||||
one_message = {}
|
||||
|
||||
if hasattr(message, 'status'):
|
||||
|
@ -13,82 +13,91 @@ class TestContentView:
|
||||
|
||||
def test_get_view_func(self):
|
||||
f = cv.get_view_func(
|
||||
cv.VIEW_HEX,
|
||||
cv.get("Hex"),
|
||||
flow.ODictCaseless(),
|
||||
"foo"
|
||||
)
|
||||
assert f is cv.view_hex
|
||||
assert f.name == "Hex"
|
||||
|
||||
f = cv.get_view_func(
|
||||
cv.VIEW_AUTO,
|
||||
cv.get("Auto"),
|
||||
flow.ODictCaseless(),
|
||||
"foo"
|
||||
)
|
||||
assert f is cv.view_raw
|
||||
assert f.name == "Raw"
|
||||
|
||||
f = cv.get_view_func(
|
||||
cv.VIEW_AUTO,
|
||||
cv.get("Auto"),
|
||||
flow.ODictCaseless(
|
||||
[["content-type", "text/html"]],
|
||||
),
|
||||
"foo"
|
||||
)
|
||||
assert f is cv.view_html
|
||||
assert f.name == "HTML"
|
||||
|
||||
f = cv.get_view_func(
|
||||
cv.VIEW_AUTO,
|
||||
cv.get("Auto"),
|
||||
flow.ODictCaseless(
|
||||
[["content-type", "text/flibble"]],
|
||||
),
|
||||
"foo"
|
||||
)
|
||||
assert f is cv.view_raw
|
||||
assert f.name == "Raw"
|
||||
|
||||
f = cv.get_view_func(
|
||||
cv.VIEW_AUTO,
|
||||
cv.get("Auto"),
|
||||
flow.ODictCaseless(
|
||||
[["content-type", "text/flibble"]],
|
||||
),
|
||||
"<xml></xml>"
|
||||
)
|
||||
assert f is cv.view_xml
|
||||
assert f.name == "XML"
|
||||
|
||||
try:
|
||||
import pyamf
|
||||
|
||||
f = cv.get_view_func(
|
||||
cv.VIEW_AUTO,
|
||||
cv.get("Auto"),
|
||||
flow.ODictCaseless(
|
||||
[["content-type", "application/x-amf"]],
|
||||
),
|
||||
""
|
||||
)
|
||||
assert f is cv.view_amf
|
||||
assert f.name == "AMF"
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
def test_view_urlencoded(self):
|
||||
d = utils.urlencode([("one", "two"), ("three", "four")])
|
||||
assert cv.view_urlencoded([], d, 100)
|
||||
assert not cv.view_urlencoded([], "foo", 100)
|
||||
v = cv.ViewURLEncoded()
|
||||
assert v([], d, 100)
|
||||
assert not v([], "foo", 100)
|
||||
|
||||
def test_view_html(self):
|
||||
v = cv.ViewHTML()
|
||||
s = "<html><br><br></br><p>one</p></html>"
|
||||
assert cv.view_html([], s, 1000)
|
||||
assert v([], s, 1000)
|
||||
|
||||
s = "gobbledygook"
|
||||
assert not cv.view_html([], s, 1000)
|
||||
assert not v([], s, 1000)
|
||||
|
||||
def test_view_html_outline(self):
|
||||
v = cv.ViewHTMLOutline()
|
||||
s = "<html><br><br></br><p>one</p></html>"
|
||||
assert v([], s, 1000)
|
||||
|
||||
def test_view_json(self):
|
||||
cv.VIEW_CUTOFF = 100
|
||||
assert cv.view_json([], "{}", 1000)
|
||||
assert not cv.view_json([], "{", 1000)
|
||||
assert cv.view_json([], "[" + ",".join(["0"]*cv.VIEW_CUTOFF) + "]", 1000)
|
||||
assert cv.view_json([], "[1, 2, 3, 4, 5]", 5)
|
||||
v = cv.ViewJSON()
|
||||
assert v([], "{}", 1000)
|
||||
assert not v([], "{", 1000)
|
||||
assert v([], "[" + ",".join(["0"]*cv.VIEW_CUTOFF) + "]", 1000)
|
||||
assert v([], "[1, 2, 3, 4, 5]", 5)
|
||||
|
||||
def test_view_xml(self):
|
||||
assert cv.view_xml([], "<foo></foo>", 1000)
|
||||
assert not cv.view_xml([], "<foo>", 1000)
|
||||
v = cv.ViewXML()
|
||||
assert v([], "<foo></foo>", 1000)
|
||||
assert not v([], "<foo>", 1000)
|
||||
s = """<?xml version="1.0" encoding="UTF-8"?>
|
||||
<?xml-stylesheet title="XSL_formatting"?>
|
||||
<rss
|
||||
@ -97,44 +106,49 @@ class TestContentView:
|
||||
version="2.0">
|
||||
</rss>
|
||||
"""
|
||||
assert cv.view_xml([], s, 1000)
|
||||
assert v([], s, 1000)
|
||||
|
||||
def test_view_raw(self):
|
||||
assert cv.view_raw([], "foo", 1000)
|
||||
v = cv.ViewRaw()
|
||||
assert v([], "foo", 1000)
|
||||
|
||||
def test_view_javascript(self):
|
||||
assert cv.view_javascript([], "[1, 2, 3]", 100)
|
||||
assert cv.view_javascript([], "[1, 2, 3", 100)
|
||||
assert cv.view_javascript([], "function(a){[1, 2, 3]}", 100)
|
||||
v = cv.ViewJavaScript()
|
||||
assert v([], "[1, 2, 3]", 100)
|
||||
assert v([], "[1, 2, 3", 100)
|
||||
assert v([], "function(a){[1, 2, 3]}", 100)
|
||||
|
||||
def test_view_hex(self):
|
||||
assert cv.view_hex([], "foo", 1000)
|
||||
v = cv.ViewHex()
|
||||
assert v([], "foo", 1000)
|
||||
|
||||
def test_view_image(self):
|
||||
v = cv.ViewImage()
|
||||
p = tutils.test_data.path("data/image.png")
|
||||
assert cv.view_image([], file(p).read(), sys.maxint)
|
||||
assert v([], file(p).read(), sys.maxint)
|
||||
|
||||
p = tutils.test_data.path("data/image.gif")
|
||||
assert cv.view_image([], file(p).read(), sys.maxint)
|
||||
assert v([], file(p).read(), sys.maxint)
|
||||
|
||||
p = tutils.test_data.path("data/image-err1.jpg")
|
||||
assert cv.view_image([], file(p).read(), sys.maxint)
|
||||
assert v([], file(p).read(), sys.maxint)
|
||||
|
||||
p = tutils.test_data.path("data/image.ico")
|
||||
assert cv.view_image([], file(p).read(), sys.maxint)
|
||||
assert v([], file(p).read(), sys.maxint)
|
||||
|
||||
assert not cv.view_image([], "flibble", sys.maxint)
|
||||
assert not v([], "flibble", sys.maxint)
|
||||
|
||||
def test_view_amf(self):
|
||||
try:
|
||||
import pyamf
|
||||
|
||||
v = cv.ViewAMF()
|
||||
p = tutils.test_data.path("data/test.amf")
|
||||
assert cv.view_amf([], file(p).read(), sys.maxint)
|
||||
assert v([], file(p).read(), sys.maxint)
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
def test_view_multipart(self):
|
||||
view = cv.ViewMultipart()
|
||||
v = """
|
||||
--AaB03x
|
||||
Content-Disposition: form-data; name="submit-name"
|
||||
@ -145,24 +159,24 @@ Larry
|
||||
h = flow.ODictCaseless(
|
||||
[("Content-Type", "multipart/form-data; boundary=AaB03x")]
|
||||
)
|
||||
assert cv.view_multipart(h, v, 1000)
|
||||
assert view(h, v, 1000)
|
||||
|
||||
h = flow.ODictCaseless()
|
||||
assert not cv.view_multipart(h, v, 1000)
|
||||
assert not view(h, v, 1000)
|
||||
|
||||
h = flow.ODictCaseless(
|
||||
[("Content-Type", "multipart/form-data")]
|
||||
)
|
||||
assert not cv.view_multipart(h, v, 1000)
|
||||
assert not view(h, v, 1000)
|
||||
|
||||
h = flow.ODictCaseless(
|
||||
[("Content-Type", "unparseable")]
|
||||
)
|
||||
assert not cv.view_multipart(h, v, 1000)
|
||||
assert not view(h, v, 1000)
|
||||
|
||||
def test_get_content_view(self):
|
||||
r = cv.get_content_view(
|
||||
cv.VIEW_RAW,
|
||||
cv.get("Raw"),
|
||||
[["content-type", "application/json"]],
|
||||
"[1, 2, 3]",
|
||||
1000
|
||||
@ -170,7 +184,7 @@ Larry
|
||||
assert "Raw" in r[0]
|
||||
|
||||
r = cv.get_content_view(
|
||||
cv.VIEW_AUTO,
|
||||
cv.get("Auto"),
|
||||
[["content-type", "application/json"]],
|
||||
"[1, 2, 3]",
|
||||
1000
|
||||
@ -178,7 +192,7 @@ Larry
|
||||
assert r[0] == "JSON"
|
||||
|
||||
r = cv.get_content_view(
|
||||
cv.VIEW_AUTO,
|
||||
cv.get("Auto"),
|
||||
[["content-type", "application/json"]],
|
||||
"[1, 2",
|
||||
1000
|
||||
@ -186,7 +200,7 @@ Larry
|
||||
assert "Raw" in r[0]
|
||||
|
||||
r = cv.get_content_view(
|
||||
cv.VIEW_AUTO,
|
||||
cv.get("Auto"),
|
||||
[
|
||||
["content-type", "application/json"],
|
||||
["content-encoding", "gzip"]
|
||||
@ -198,7 +212,7 @@ Larry
|
||||
assert "JSON" in r[0]
|
||||
|
||||
r = cv.get_content_view(
|
||||
cv.VIEW_XML,
|
||||
cv.get("XML"),
|
||||
[
|
||||
["content-type", "application/json"],
|
||||
["content-encoding", "gzip"]
|
||||
|
Loading…
Reference in New Issue
Block a user