mirror of
https://github.com/Grasscutters/mitmproxy.git
synced 2024-11-26 02:10:59 +00:00
commit
e0c5f86b20
@ -1,9 +1,14 @@
|
||||
from __future__ import absolute_import
|
||||
import urwid
|
||||
import urwid.util
|
||||
import os
|
||||
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_FLOW = 1
|
||||
@ -162,6 +167,146 @@ def raw_format_flow(f, focus, extended, padding):
|
||||
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:
|
||||
@utils.LRUCache(200)
|
||||
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)
|
||||
|
||||
|
||||
|
||||
def int_version(v):
|
||||
SIG = 3
|
||||
v = urwid.__version__.split("-")[0].split(".")
|
||||
|
@ -7,11 +7,13 @@ def _mkhelp():
|
||||
keys = [
|
||||
("A", "accept all intercepted flows"),
|
||||
("a", "accept this intercepted flow"),
|
||||
("b", "save request/response body"),
|
||||
("C", "clear flow list or eventlog"),
|
||||
("d", "delete flow"),
|
||||
("D", "duplicate flow"),
|
||||
("e", "toggle eventlog"),
|
||||
("F", "toggle follow flow list"),
|
||||
("g", "copy flow to clipboard"),
|
||||
("l", "set limit filter pattern"),
|
||||
("L", "load saved flows"),
|
||||
("r", "replay request"),
|
||||
@ -204,6 +206,10 @@ class ConnectionItem(common.WWrap):
|
||||
self.master.run_script_once,
|
||||
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:
|
||||
return key
|
||||
|
||||
|
@ -19,6 +19,7 @@ def _mkhelp():
|
||||
("D", "duplicate flow"),
|
||||
("e", "edit request/response"),
|
||||
("f", "load full body data"),
|
||||
("g", "copy response(content/headers) to clipboard"),
|
||||
("m", "change body display mode for this entity"),
|
||||
(None,
|
||||
common.highlight_key("automatic", "a") +
|
||||
@ -508,22 +509,6 @@ class FlowView(common.WWrap):
|
||||
self.flow.request.method = i[0].upper()
|
||||
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):
|
||||
request = self.flow.request
|
||||
try:
|
||||
@ -689,19 +674,10 @@ class FlowView(common.WWrap):
|
||||
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
|
||||
)
|
||||
common.ask_save_body("q", self.master, self.state, self.flow)
|
||||
else:
|
||||
self.master.path_prompt(
|
||||
"Save response body: ",
|
||||
self.state.last_saveload,
|
||||
self.save_body
|
||||
)
|
||||
common.ask_save_body("s", self.master, self.state, self.flow)
|
||||
elif key == "d":
|
||||
if self.state.flow_count() == 1:
|
||||
self.master.view_flowlist()
|
||||
@ -752,6 +728,12 @@ class FlowView(common.WWrap):
|
||||
)
|
||||
self.master.refresh_flow(self.flow)
|
||||
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":
|
||||
p = list(contentview.view_prompts)
|
||||
p.insert(0, ("Clear", "C"))
|
||||
|
Loading…
Reference in New Issue
Block a user