mirror of
https://github.com/Grasscutters/mitmproxy.git
synced 2024-11-29 11:03:13 +00:00
commit
e0c5f86b20
@ -1,9 +1,14 @@
|
|||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
import urwid
|
import urwid
|
||||||
import urwid.util
|
import urwid.util
|
||||||
|
import os
|
||||||
from .. import utils
|
from .. import utils
|
||||||
from ..protocol.http import CONTENT_MISSING
|
from ..protocol.http import CONTENT_MISSING, decoded
|
||||||
|
|
||||||
|
try:
|
||||||
|
import pyperclip
|
||||||
|
except:
|
||||||
|
pyperclip = False
|
||||||
|
|
||||||
VIEW_LIST = 0
|
VIEW_LIST = 0
|
||||||
VIEW_FLOW = 1
|
VIEW_FLOW = 1
|
||||||
@ -162,6 +167,146 @@ def raw_format_flow(f, focus, extended, padding):
|
|||||||
return urwid.Pile(pile)
|
return urwid.Pile(pile)
|
||||||
|
|
||||||
|
|
||||||
|
# Save file to disk
|
||||||
|
def save_data(path, data, master, state):
|
||||||
|
if not path:
|
||||||
|
return
|
||||||
|
state.last_saveload = path
|
||||||
|
path = os.path.expanduser(path)
|
||||||
|
try:
|
||||||
|
with file(path, "wb") as f:
|
||||||
|
f.write(data)
|
||||||
|
except IOError, v:
|
||||||
|
master.statusbar.message(v.strerror)
|
||||||
|
|
||||||
|
|
||||||
|
def ask_save_path(prompt, data, master, state):
|
||||||
|
master.path_prompt(
|
||||||
|
prompt,
|
||||||
|
state.last_saveload,
|
||||||
|
save_data,
|
||||||
|
data,
|
||||||
|
master,
|
||||||
|
state
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def copy_flow_format_data(part, scope, flow):
|
||||||
|
if part == "u":
|
||||||
|
data = flow.request.url
|
||||||
|
else:
|
||||||
|
data = ""
|
||||||
|
if scope in ("q", "a"):
|
||||||
|
with decoded(flow.request):
|
||||||
|
if part == "h":
|
||||||
|
data += flow.request.assemble()
|
||||||
|
elif part == "c":
|
||||||
|
data += flow.request.content
|
||||||
|
else:
|
||||||
|
raise ValueError("Unknown part: {}".format(part))
|
||||||
|
if scope == "a" and flow.request.content and flow.response:
|
||||||
|
# Add padding between request and response
|
||||||
|
data += "\r\n" * 2
|
||||||
|
if scope in ("s", "a") and flow.response:
|
||||||
|
with decoded(flow.response):
|
||||||
|
if part == "h":
|
||||||
|
data += flow.response.assemble()
|
||||||
|
elif part == "c":
|
||||||
|
data += flow.response.content
|
||||||
|
else:
|
||||||
|
raise ValueError("Unknown part: {}".format(part))
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
def copy_flow(part, scope, flow, master, state):
|
||||||
|
"""
|
||||||
|
part: _c_ontent, _a_ll, _u_rl
|
||||||
|
scope: _a_ll, re_q_uest, re_s_ponse
|
||||||
|
"""
|
||||||
|
data = copy_flow_format_data(part, scope, flow)
|
||||||
|
|
||||||
|
if not data:
|
||||||
|
if scope == "q":
|
||||||
|
master.statusbar.message("No request content to copy.")
|
||||||
|
elif scope == "s":
|
||||||
|
master.statusbar.message("No response content to copy.")
|
||||||
|
else:
|
||||||
|
master.statusbar.message("No contents to copy.")
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
master.add_event(str(len(data)))
|
||||||
|
pyperclip.copy(data)
|
||||||
|
except RuntimeError:
|
||||||
|
def save(k):
|
||||||
|
if k == "y":
|
||||||
|
ask_save_path("Save data: ", data, master, state)
|
||||||
|
|
||||||
|
master.prompt_onekey(
|
||||||
|
"Cannot copy binary data to clipboard. Save as file?",
|
||||||
|
(
|
||||||
|
("yes", "y"),
|
||||||
|
("no", "n"),
|
||||||
|
),
|
||||||
|
save
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def ask_copy_part(scope, flow, master, state):
|
||||||
|
choices = [
|
||||||
|
("content", "c"),
|
||||||
|
("headers+content", "h")
|
||||||
|
]
|
||||||
|
if scope != "s":
|
||||||
|
choices.append(("url", "u"))
|
||||||
|
|
||||||
|
master.prompt_onekey(
|
||||||
|
"Copy",
|
||||||
|
choices,
|
||||||
|
copy_flow,
|
||||||
|
scope,
|
||||||
|
flow,
|
||||||
|
master,
|
||||||
|
state
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def ask_save_body(part, master, state, flow):
|
||||||
|
"""
|
||||||
|
Save either the request or the response body to disk.
|
||||||
|
part can either be "q" (request), "s" (response) or None (ask user if necessary).
|
||||||
|
"""
|
||||||
|
|
||||||
|
request_has_content = flow.request and flow.request.content
|
||||||
|
response_has_content = flow.response and flow.response.content
|
||||||
|
|
||||||
|
if part is None:
|
||||||
|
# We first need to determine whether we want to save the request or the response content.
|
||||||
|
if request_has_content and response_has_content:
|
||||||
|
master.prompt_onekey(
|
||||||
|
"Save",
|
||||||
|
(
|
||||||
|
("request", "q"),
|
||||||
|
("response", "s"),
|
||||||
|
),
|
||||||
|
ask_save_body,
|
||||||
|
master,
|
||||||
|
state,
|
||||||
|
flow
|
||||||
|
)
|
||||||
|
elif response_has_content:
|
||||||
|
ask_save_body("s", master, state, flow)
|
||||||
|
else:
|
||||||
|
ask_save_body("q", master, state, flow)
|
||||||
|
|
||||||
|
elif part == "q" and request_has_content:
|
||||||
|
ask_save_path("Save request content: ", flow.request.get_decoded_content(), master, state)
|
||||||
|
elif part == "s" and response_has_content:
|
||||||
|
ask_save_path("Save response content: ", flow.response.get_decoded_content(), master, state)
|
||||||
|
else:
|
||||||
|
master.statusbar.message("No content to save.")
|
||||||
|
|
||||||
|
|
||||||
class FlowCache:
|
class FlowCache:
|
||||||
@utils.LRUCache(200)
|
@utils.LRUCache(200)
|
||||||
def format_flow(self, *args):
|
def format_flow(self, *args):
|
||||||
@ -211,7 +356,6 @@ def format_flow(f, focus, extended=False, hostheader=False, padding=2):
|
|||||||
return flowcache.format_flow(tuple(sorted(d.items())), focus, extended, padding)
|
return flowcache.format_flow(tuple(sorted(d.items())), focus, extended, padding)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def int_version(v):
|
def int_version(v):
|
||||||
SIG = 3
|
SIG = 3
|
||||||
v = urwid.__version__.split("-")[0].split(".")
|
v = urwid.__version__.split("-")[0].split(".")
|
||||||
|
@ -7,11 +7,13 @@ def _mkhelp():
|
|||||||
keys = [
|
keys = [
|
||||||
("A", "accept all intercepted flows"),
|
("A", "accept all intercepted flows"),
|
||||||
("a", "accept this intercepted flow"),
|
("a", "accept this intercepted flow"),
|
||||||
|
("b", "save request/response body"),
|
||||||
("C", "clear flow list or eventlog"),
|
("C", "clear flow list or eventlog"),
|
||||||
("d", "delete flow"),
|
("d", "delete flow"),
|
||||||
("D", "duplicate flow"),
|
("D", "duplicate flow"),
|
||||||
("e", "toggle eventlog"),
|
("e", "toggle eventlog"),
|
||||||
("F", "toggle follow flow list"),
|
("F", "toggle follow flow list"),
|
||||||
|
("g", "copy flow to clipboard"),
|
||||||
("l", "set limit filter pattern"),
|
("l", "set limit filter pattern"),
|
||||||
("L", "load saved flows"),
|
("L", "load saved flows"),
|
||||||
("r", "replay request"),
|
("r", "replay request"),
|
||||||
@ -204,6 +206,10 @@ class ConnectionItem(common.WWrap):
|
|||||||
self.master.run_script_once,
|
self.master.run_script_once,
|
||||||
self.flow
|
self.flow
|
||||||
)
|
)
|
||||||
|
elif key == "g":
|
||||||
|
common.ask_copy_part("a", self.flow, self.master, self.state)
|
||||||
|
elif key == "b":
|
||||||
|
common.ask_save_body(None, self.master, self.state, self.flow)
|
||||||
else:
|
else:
|
||||||
return key
|
return key
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@ def _mkhelp():
|
|||||||
("D", "duplicate flow"),
|
("D", "duplicate flow"),
|
||||||
("e", "edit request/response"),
|
("e", "edit request/response"),
|
||||||
("f", "load full body data"),
|
("f", "load full body data"),
|
||||||
|
("g", "copy response(content/headers) to clipboard"),
|
||||||
("m", "change body display mode for this entity"),
|
("m", "change body display mode for this entity"),
|
||||||
(None,
|
(None,
|
||||||
common.highlight_key("automatic", "a") +
|
common.highlight_key("automatic", "a") +
|
||||||
@ -508,22 +509,6 @@ class FlowView(common.WWrap):
|
|||||||
self.flow.request.method = i[0].upper()
|
self.flow.request.method = i[0].upper()
|
||||||
self.master.refresh_flow(self.flow)
|
self.master.refresh_flow(self.flow)
|
||||||
|
|
||||||
def save_body(self, path):
|
|
||||||
if not path:
|
|
||||||
return
|
|
||||||
self.state.last_saveload = path
|
|
||||||
if self.state.view_flow_mode == common.VIEW_FLOW_REQUEST:
|
|
||||||
c = self.flow.request
|
|
||||||
else:
|
|
||||||
c = self.flow.response
|
|
||||||
path = os.path.expanduser(path)
|
|
||||||
try:
|
|
||||||
f = file(path, "wb")
|
|
||||||
f.write(str(c.content))
|
|
||||||
f.close()
|
|
||||||
except IOError, v:
|
|
||||||
self.master.statusbar.message(v.strerror)
|
|
||||||
|
|
||||||
def set_url(self, url):
|
def set_url(self, url):
|
||||||
request = self.flow.request
|
request = self.flow.request
|
||||||
try:
|
try:
|
||||||
@ -689,19 +674,10 @@ class FlowView(common.WWrap):
|
|||||||
self.master.accept_all()
|
self.master.accept_all()
|
||||||
self.master.view_flow(self.flow)
|
self.master.view_flow(self.flow)
|
||||||
elif key == "b":
|
elif key == "b":
|
||||||
if conn:
|
|
||||||
if self.state.view_flow_mode == common.VIEW_FLOW_REQUEST:
|
if self.state.view_flow_mode == common.VIEW_FLOW_REQUEST:
|
||||||
self.master.path_prompt(
|
common.ask_save_body("q", self.master, self.state, self.flow)
|
||||||
"Save request body: ",
|
|
||||||
self.state.last_saveload,
|
|
||||||
self.save_body
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
self.master.path_prompt(
|
common.ask_save_body("s", self.master, self.state, self.flow)
|
||||||
"Save response body: ",
|
|
||||||
self.state.last_saveload,
|
|
||||||
self.save_body
|
|
||||||
)
|
|
||||||
elif key == "d":
|
elif key == "d":
|
||||||
if self.state.flow_count() == 1:
|
if self.state.flow_count() == 1:
|
||||||
self.master.view_flowlist()
|
self.master.view_flowlist()
|
||||||
@ -752,6 +728,12 @@ class FlowView(common.WWrap):
|
|||||||
)
|
)
|
||||||
self.master.refresh_flow(self.flow)
|
self.master.refresh_flow(self.flow)
|
||||||
self.master.statusbar.message("")
|
self.master.statusbar.message("")
|
||||||
|
elif key == "g":
|
||||||
|
if self.state.view_flow_mode == common.VIEW_FLOW_REQUEST:
|
||||||
|
scope = "q"
|
||||||
|
else:
|
||||||
|
scope = "s"
|
||||||
|
common.ask_copy_part(scope, self.flow, self.master, self.state)
|
||||||
elif key == "m":
|
elif key == "m":
|
||||||
p = list(contentview.view_prompts)
|
p = list(contentview.view_prompts)
|
||||||
p.insert(0, ("Clear", "C"))
|
p.insert(0, ("Clear", "C"))
|
||||||
|
Loading…
Reference in New Issue
Block a user