mirror of
https://github.com/Grasscutters/mitmproxy.git
synced 2024-11-23 00:01:36 +00:00
Add an "f" shortcut key to load full body contents.
This commit is contained in:
parent
618a9c0e2b
commit
4e2d19714c
@ -234,6 +234,7 @@ class StatusBar(common.WWrap):
|
||||
else:
|
||||
self.expire = None
|
||||
self.ab.message(msg)
|
||||
self.master.drawscreen()
|
||||
|
||||
|
||||
#end nocover
|
||||
|
@ -7,7 +7,7 @@ import common
|
||||
from .. import utils, encoding, flow
|
||||
from ..contrib import jsbeautifier
|
||||
|
||||
VIEW_CUTOFF = 1024*100
|
||||
VIEW_CUTOFF = 1024*50
|
||||
|
||||
VIEW_AUTO = 0
|
||||
VIEW_JSON = 1
|
||||
@ -76,20 +76,22 @@ CONTENT_TYPES_MAP = {
|
||||
"image/x-icon": VIEW_IMAGE,
|
||||
}
|
||||
|
||||
def trailer(clen, txt):
|
||||
rem = clen - VIEW_CUTOFF
|
||||
def trailer(clen, txt, limit):
|
||||
rem = clen - limit
|
||||
if rem > 0:
|
||||
txt.append(urwid.Text(""))
|
||||
txt.append(
|
||||
urwid.Text(
|
||||
[
|
||||
("highlight", "... %s of data not shown"%utils.pretty_size(rem))
|
||||
("highlight", "... %s of data not shown. Press "%utils.pretty_size(rem)),
|
||||
("key", "f"),
|
||||
("highlight", " to load all data.")
|
||||
]
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def _view_text(content, total):
|
||||
def _view_text(content, total, limit):
|
||||
"""
|
||||
Generates a body for a chunk of text.
|
||||
"""
|
||||
@ -98,18 +100,18 @@ def _view_text(content, total):
|
||||
txt.append(
|
||||
urwid.Text(("text", i), wrap="any")
|
||||
)
|
||||
trailer(total, txt)
|
||||
trailer(total, txt, limit)
|
||||
return txt
|
||||
|
||||
|
||||
def view_raw(hdrs, content):
|
||||
txt = _view_text(content[:VIEW_CUTOFF], len(content))
|
||||
def view_raw(hdrs, content, limit):
|
||||
txt = _view_text(content[:limit], len(content), limit)
|
||||
return "Raw", txt
|
||||
|
||||
|
||||
def view_hex(hdrs, content):
|
||||
def view_hex(hdrs, content, limit):
|
||||
txt = []
|
||||
for offset, hexa, s in utils.hexdump(content[:VIEW_CUTOFF]):
|
||||
for offset, hexa, s in utils.hexdump(content[:limit]):
|
||||
txt.append(urwid.Text([
|
||||
("offset", offset),
|
||||
" ",
|
||||
@ -117,11 +119,11 @@ def view_hex(hdrs, content):
|
||||
" ",
|
||||
("text", s),
|
||||
]))
|
||||
trailer(len(content), txt)
|
||||
trailer(len(content), txt, limit)
|
||||
return "Hex", txt
|
||||
|
||||
|
||||
def view_xml(hdrs, content):
|
||||
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)
|
||||
@ -151,24 +153,24 @@ def view_xml(hdrs, content):
|
||||
)
|
||||
|
||||
txt = []
|
||||
for i in s[:VIEW_CUTOFF].strip().split("\n"):
|
||||
for i in s[:limit].strip().split("\n"):
|
||||
txt.append(
|
||||
urwid.Text(("text", i)),
|
||||
)
|
||||
trailer(len(content), txt)
|
||||
trailer(len(content), txt, limit)
|
||||
return "XML-like data", txt
|
||||
|
||||
|
||||
def view_html(hdrs, content):
|
||||
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[:VIEW_CUTOFF], len(s))
|
||||
return "HTML", _view_text(s[:limit], len(s), limit)
|
||||
|
||||
|
||||
def view_json(hdrs, content):
|
||||
def view_json(hdrs, content, limit):
|
||||
lines = utils.pretty_json(content)
|
||||
if lines:
|
||||
txt = []
|
||||
@ -178,13 +180,13 @@ def view_json(hdrs, content):
|
||||
txt.append(
|
||||
urwid.Text(("text", i)),
|
||||
)
|
||||
if sofar > VIEW_CUTOFF:
|
||||
if sofar > limit:
|
||||
break
|
||||
trailer(sum(len(i) for i in lines), txt)
|
||||
trailer(sum(len(i) for i in lines), txt, limit)
|
||||
return "JSON", txt
|
||||
|
||||
|
||||
def view_multipart(hdrs, content):
|
||||
def view_multipart(hdrs, content, limit):
|
||||
v = hdrs.get("content-type")
|
||||
if v:
|
||||
v = utils.parse_content_type(v[0])
|
||||
@ -218,7 +220,7 @@ def view_multipart(hdrs, content):
|
||||
return "Multipart form", r
|
||||
|
||||
|
||||
def view_urlencoded(hdrs, content):
|
||||
def view_urlencoded(hdrs, content, limit):
|
||||
lines = utils.urldecode(content)
|
||||
if lines:
|
||||
body = common.format_keyvals(
|
||||
@ -229,18 +231,20 @@ def view_urlencoded(hdrs, content):
|
||||
return "URLEncoded form", body
|
||||
|
||||
|
||||
def view_javascript(hdrs, content):
|
||||
def view_javascript(hdrs, content, limit):
|
||||
opts = jsbeautifier.default_options()
|
||||
opts.indent_size = 2
|
||||
try:
|
||||
res = jsbeautifier.beautify(content[:VIEW_CUTOFF], opts)
|
||||
res = jsbeautifier.beautify(content[:limit], opts)
|
||||
# begin nocover
|
||||
except:
|
||||
# Bugs in jsbeautifier mean that it can trhow arbitrary errors.
|
||||
return None
|
||||
return "JavaScript", _view_text(res, len(content))
|
||||
# end nocover
|
||||
return "JavaScript", _view_text(res, len(content), limit)
|
||||
|
||||
|
||||
def view_image(hdrs, content):
|
||||
def view_image(hdrs, content, limit):
|
||||
try:
|
||||
img = Image.open(cStringIO.StringIO(content))
|
||||
except IOError:
|
||||
@ -302,7 +306,7 @@ def get_view_func(viewmode, hdrs, content):
|
||||
return PRETTY_FUNCTION_MAP.get(viewmode, view_raw)
|
||||
|
||||
|
||||
def get_content_view(viewmode, hdrItems, content):
|
||||
def get_content_view(viewmode, hdrItems, content, limit):
|
||||
"""
|
||||
Returns a (msg, body) tuple.
|
||||
"""
|
||||
@ -317,10 +321,10 @@ def get_content_view(viewmode, hdrItems, content):
|
||||
content = decoded
|
||||
msg.append("[decoded %s]"%enc[0])
|
||||
func = get_view_func(viewmode, hdrs, content)
|
||||
ret = func(hdrs, content)
|
||||
ret = func(hdrs, content, limit)
|
||||
if not ret:
|
||||
viewmode = VIEW_RAW
|
||||
ret = view_raw(hdrs, content)
|
||||
ret = view_raw(hdrs, content, limit)
|
||||
msg.append("Couldn't parse: falling back to Raw")
|
||||
else:
|
||||
msg.append(ret[0])
|
||||
|
@ -13,7 +13,7 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import os, re
|
||||
import os, re, sys
|
||||
import urwid
|
||||
import common, grideditor, contentview
|
||||
from .. import utils, encoding, flow
|
||||
@ -125,15 +125,25 @@ class FlowView(common.WWrap):
|
||||
else:
|
||||
self.view_request()
|
||||
|
||||
def _cached_content_view(self, viewmode, hdrItems, content):
|
||||
return contentview.get_content_view(viewmode, hdrItems, content)
|
||||
def _cached_content_view(self, viewmode, hdrItems, content, limit):
|
||||
return contentview.get_content_view(viewmode, hdrItems, content, limit)
|
||||
|
||||
def content_view(self, viewmode, conn):
|
||||
full = self.state.get_flow_setting(
|
||||
self.flow,
|
||||
(self.state.view_flow_mode, "fullcontents"),
|
||||
False
|
||||
)
|
||||
if full:
|
||||
limit = sys.maxint
|
||||
else:
|
||||
limit = contentview.VIEW_CUTOFF
|
||||
return cache.callback(
|
||||
self, "_cached_content_view",
|
||||
viewmode,
|
||||
tuple(tuple(i) for i in conn.headers.lst),
|
||||
conn.content,
|
||||
limit
|
||||
)
|
||||
|
||||
def conn_text(self, conn):
|
||||
@ -407,6 +417,20 @@ class FlowView(common.WWrap):
|
||||
elif key == "A":
|
||||
self.master.accept_all()
|
||||
self.master.view_flow(self.flow)
|
||||
elif key == "b":
|
||||
if conn:
|
||||
if self.state.view_flow_mode == common.VIEW_FLOW_REQUEST:
|
||||
self.master.path_prompt(
|
||||
"Save request body: ",
|
||||
self.state.last_saveload,
|
||||
self.save_body
|
||||
)
|
||||
else:
|
||||
self.master.path_prompt(
|
||||
"Save response body: ",
|
||||
self.state.last_saveload,
|
||||
self.save_body
|
||||
)
|
||||
elif key == "d":
|
||||
if self.state.flow_count() == 1:
|
||||
self.master.view_flowlist()
|
||||
@ -448,6 +472,15 @@ class FlowView(common.WWrap):
|
||||
self.edit
|
||||
)
|
||||
key = None
|
||||
elif key == "f":
|
||||
self.master.statusbar.message("Loading all body data...")
|
||||
self.state.add_flow_setting(
|
||||
self.flow,
|
||||
(self.state.view_flow_mode, "fullcontents"),
|
||||
True
|
||||
)
|
||||
self.master.refresh_flow(self.flow)
|
||||
self.master.statusbar.message("")
|
||||
elif key == "m":
|
||||
p = list(contentview.VIEW_PROMPT)
|
||||
p.insert(0, ("clear", "c"))
|
||||
@ -484,20 +517,6 @@ class FlowView(common.WWrap):
|
||||
t = conn.headers["content-type"] or [None]
|
||||
t = t[0]
|
||||
self.master.spawn_external_viewer(conn.content, t)
|
||||
elif key == "b":
|
||||
if conn:
|
||||
if self.state.view_flow_mode == common.VIEW_FLOW_REQUEST:
|
||||
self.master.path_prompt(
|
||||
"Save request body: ",
|
||||
self.state.last_saveload,
|
||||
self.save_body
|
||||
)
|
||||
else:
|
||||
self.master.path_prompt(
|
||||
"Save response body: ",
|
||||
self.state.last_saveload,
|
||||
self.save_body
|
||||
)
|
||||
elif key == "|":
|
||||
self.master.path_prompt(
|
||||
"Send flow to script: ", self.state.last_script,
|
||||
|
@ -1,3 +1,4 @@
|
||||
import sys
|
||||
import libpry
|
||||
import libmproxy.console.contentview as cv
|
||||
from libmproxy import utils, flow, encoding
|
||||
@ -5,9 +6,9 @@ from libmproxy import utils, flow, encoding
|
||||
class uContentView(libpry.AutoTree):
|
||||
def test_trailer(self):
|
||||
txt = []
|
||||
cv.trailer(5, txt)
|
||||
cv.trailer(5, txt, 1000)
|
||||
assert not txt
|
||||
cv.trailer(cv.VIEW_CUTOFF + 10, txt)
|
||||
cv.trailer(cv.VIEW_CUTOFF + 10, txt, cv.VIEW_CUTOFF)
|
||||
assert txt
|
||||
|
||||
def test_get_view_func(self):
|
||||
@ -54,25 +55,26 @@ class uContentView(libpry.AutoTree):
|
||||
|
||||
def test_view_urlencoded(self):
|
||||
d = utils.urlencode([("one", "two"), ("three", "four")])
|
||||
assert cv.view_urlencoded([], d)
|
||||
assert not cv.view_urlencoded([], "foo")
|
||||
assert cv.view_urlencoded([], d, 100)
|
||||
assert not cv.view_urlencoded([], "foo", 100)
|
||||
|
||||
def test_view_html(self):
|
||||
s = "<html><br><br></br><p>one</p></html>"
|
||||
assert cv.view_html([], s)
|
||||
assert cv.view_html([], s, 1000)
|
||||
|
||||
s = "gobbledygook"
|
||||
assert not cv.view_html([], s)
|
||||
assert not cv.view_html([], s, 1000)
|
||||
|
||||
def test_view_json(self):
|
||||
cv.VIEW_CUTOFF = 100
|
||||
assert cv.view_json([], "{}")
|
||||
assert not cv.view_urlencoded([], "{")
|
||||
assert cv.view_json([], "[" + ",".join(["0"]*cv.VIEW_CUTOFF) + "]")
|
||||
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)
|
||||
|
||||
def test_view_xml(self):
|
||||
assert cv.view_xml([], "<foo></foo>")
|
||||
assert not cv.view_xml([], "<foo>")
|
||||
assert cv.view_xml([], "<foo></foo>", 1000)
|
||||
assert not cv.view_xml([], "<foo>", 1000)
|
||||
s = """<?xml version="1.0" encoding="UTF-8"?>
|
||||
<?xml-stylesheet title="XSL_formatting"?>
|
||||
<rss
|
||||
@ -81,25 +83,25 @@ class uContentView(libpry.AutoTree):
|
||||
version="2.0">
|
||||
</rss>
|
||||
"""
|
||||
assert cv.view_xml([], s)
|
||||
assert cv.view_xml([], s, 1000)
|
||||
|
||||
def test_view_raw(self):
|
||||
assert cv.view_raw([], "foo")
|
||||
assert cv.view_raw([], "foo", 1000)
|
||||
|
||||
def test_view_javascript(self):
|
||||
assert cv.view_javascript([], "[1, 2, 3]")
|
||||
assert cv.view_javascript([], "[1, 2, 3")
|
||||
assert cv.view_javascript([], "function(a){[1, 2, 3]}")
|
||||
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)
|
||||
|
||||
def test_view_raw(self):
|
||||
assert cv.view_hex([], "foo")
|
||||
def test_view_hex(self):
|
||||
assert cv.view_hex([], "foo", 1000)
|
||||
|
||||
def test_view_image(self):
|
||||
assert cv.view_image([], file("data/image.png").read())
|
||||
assert cv.view_image([], file("data/image.gif").read())
|
||||
assert cv.view_image([], file("data/image-err1.jpg").read())
|
||||
assert cv.view_image([], file("data/image.ico").read())
|
||||
assert not cv.view_image([], "flibble")
|
||||
assert cv.view_image([], file("data/image.png").read(), sys.maxint)
|
||||
assert cv.view_image([], file("data/image.gif").read(), sys.maxint)
|
||||
assert cv.view_image([], file("data/image-err1.jpg").read(), sys.maxint)
|
||||
assert cv.view_image([], file("data/image.ico").read(), sys.maxint)
|
||||
assert not cv.view_image([], "flibble", sys.maxint)
|
||||
|
||||
def test_view_multipart(self):
|
||||
v = """
|
||||
@ -112,40 +114,43 @@ Larry
|
||||
h = flow.ODictCaseless(
|
||||
[("Content-Type", "multipart/form-data; boundary=AaB03x")]
|
||||
)
|
||||
assert cv.view_multipart(h, v)
|
||||
assert cv.view_multipart(h, v, 1000)
|
||||
|
||||
h = flow.ODictCaseless()
|
||||
assert not cv.view_multipart(h, v)
|
||||
assert not cv.view_multipart(h, v, 1000)
|
||||
|
||||
h = flow.ODictCaseless(
|
||||
[("Content-Type", "multipart/form-data")]
|
||||
)
|
||||
assert not cv.view_multipart(h, v)
|
||||
assert not cv.view_multipart(h, v, 1000)
|
||||
|
||||
h = flow.ODictCaseless(
|
||||
[("Content-Type", "unparseable")]
|
||||
)
|
||||
assert not cv.view_multipart(h, v)
|
||||
assert not cv.view_multipart(h, v, 1000)
|
||||
|
||||
def test_get_content_view(self):
|
||||
r = cv.get_content_view(
|
||||
cv.VIEW_RAW,
|
||||
[["content-type", "application/json"]],
|
||||
"[1, 2, 3]"
|
||||
"[1, 2, 3]",
|
||||
1000
|
||||
)
|
||||
assert "Raw" in r[0]
|
||||
|
||||
r = cv.get_content_view(
|
||||
cv.VIEW_AUTO,
|
||||
[["content-type", "application/json"]],
|
||||
"[1, 2, 3]"
|
||||
"[1, 2, 3]",
|
||||
1000
|
||||
)
|
||||
assert r[0] == "JSON"
|
||||
|
||||
r = cv.get_content_view(
|
||||
cv.VIEW_AUTO,
|
||||
[["content-type", "application/json"]],
|
||||
"[1, 2"
|
||||
"[1, 2",
|
||||
1000
|
||||
)
|
||||
assert "Raw" in r[0]
|
||||
|
||||
@ -155,7 +160,8 @@ Larry
|
||||
["content-type", "application/json"],
|
||||
["content-encoding", "gzip"]
|
||||
],
|
||||
encoding.encode('gzip', "[1, 2, 3]")
|
||||
encoding.encode('gzip', "[1, 2, 3]"),
|
||||
1000
|
||||
)
|
||||
assert "decoded gzip" in r[0]
|
||||
assert "JSON" in r[0]
|
||||
@ -166,7 +172,8 @@ Larry
|
||||
["content-type", "application/json"],
|
||||
["content-encoding", "gzip"]
|
||||
],
|
||||
encoding.encode('gzip', "[1, 2, 3]")
|
||||
encoding.encode('gzip', "[1, 2, 3]"),
|
||||
1000
|
||||
)
|
||||
assert "decoded gzip" in r[0]
|
||||
assert "Raw" in r[0]
|
||||
|
Loading…
Reference in New Issue
Block a user