From 8725d50d03cf21b37a78c1d2fa03ade055c8a821 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Sat, 21 Mar 2015 11:19:20 +1300 Subject: Add blinker dependency, start using it to refactor console app Blinker lets us set up a central pub/sub mechanism to disentangle our object structure. --- libmproxy/console/flowview.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'libmproxy/console/flowview.py') diff --git a/libmproxy/console/flowview.py b/libmproxy/console/flowview.py index 89e75aad..b22bbb37 100644 --- a/libmproxy/console/flowview.py +++ b/libmproxy/console/flowview.py @@ -1,7 +1,7 @@ from __future__ import absolute_import import os, sys, copy import urwid -from . import common, grideditor, contentview +from . import common, grideditor, contentview, signals from .. import utils, flow, controller from ..protocol.http import HTTPRequest, HTTPResponse, CONTENT_MISSING, decoded @@ -282,10 +282,10 @@ class FlowView(urwid.WidgetWrap): if last_search_string: message = self.search(last_search_string, backwards) if message: - self.master.statusbar.message(message) + signals.status_message.send(message=message) else: message = "no previous searches have been made" - self.master.statusbar.message(message) + signals.status_message.send(message=message) return message @@ -606,7 +606,7 @@ class FlowView(urwid.WidgetWrap): else: new_flow, new_idx = self.state.get_prev(idx) if new_flow is None: - self.master.statusbar.message("No more flows!") + signals.status_message.send(message="No more flows!") return self.master.view_flow(new_flow) @@ -681,7 +681,7 @@ class FlowView(urwid.WidgetWrap): elif key == "D": f = self.master.duplicate_flow(self.flow) self.master.view_flow(f) - self.master.statusbar.message("Duplicated.") + signals.status_message.send(message="Duplicated.") elif key == "e": if self.state.view_flow_mode == common.VIEW_FLOW_REQUEST: self.master.prompt_onekey( @@ -710,14 +710,14 @@ class FlowView(urwid.WidgetWrap): ) key = None elif key == "f": - self.master.statusbar.message("Loading all body data...") + signals.status_message.send(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("") + signals.status_message.send(message="") elif key == "g": if self.state.view_flow_mode == common.VIEW_FLOW_REQUEST: scope = "q" @@ -738,15 +738,15 @@ class FlowView(urwid.WidgetWrap): elif key == "r": r = self.master.replay_request(self.flow) if r: - self.master.statusbar.message(r) + signals.status_message.send(message=r) self.master.refresh_flow(self.flow) elif key == "V": if not self.flow.modified(): - self.master.statusbar.message("Flow not modified.") + signals.status_message.send(message="Flow not modified.") return self.state.revert(self.flow) self.master.refresh_flow(self.flow) - self.master.statusbar.message("Reverted.") + signals.status_message.send(message="Reverted.") elif key == "W": self.master.path_prompt( "Save this flow: ", @@ -761,7 +761,7 @@ class FlowView(urwid.WidgetWrap): if os.environ.has_key("EDITOR") or os.environ.has_key("PAGER"): self.master.spawn_external_viewer(conn.content, t) else: - self.master.statusbar.message("Error! Set $EDITOR or $PAGER.") + signals.status_message.send(message="Error! Set $EDITOR or $PAGER.") elif key == "|": self.master.path_prompt( "Send flow to script: ", self.state.last_script, @@ -785,7 +785,7 @@ class FlowView(urwid.WidgetWrap): e = conn.headers.get_first("content-encoding", "identity") if e != "identity": if not conn.decode(): - self.master.statusbar.message("Could not decode - invalid data?") + signals.status_message.send(message="Could not decode - invalid data?") else: self.master.prompt_onekey( "Select encoding: ", -- cgit v1.2.3 From 89383e9c138f68caf1cc394174250c133d21aa04 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Sun, 22 Mar 2015 13:32:24 +1300 Subject: Refactor status bar prompting to use signal system --- libmproxy/console/flowview.py | 109 ++++++++++++++++++++++++++---------------- 1 file changed, 67 insertions(+), 42 deletions(-) (limited to 'libmproxy/console/flowview.py') diff --git a/libmproxy/console/flowview.py b/libmproxy/console/flowview.py index b22bbb37..941ceb94 100644 --- a/libmproxy/console/flowview.py +++ b/libmproxy/console/flowview.py @@ -492,7 +492,11 @@ class FlowView(urwid.WidgetWrap): def edit_method(self, m): if m == "e": - self.master.prompt_edit("Method", self.flow.request.method, self.set_method_raw) + signals.status_prompt.send( + prompt = "Method: ", + text = self.flow.request.method, + callback = self.set_method_raw + ) else: for i in common.METHOD_OPTIONS: if i[1] == m: @@ -567,14 +571,14 @@ class FlowView(urwid.WidgetWrap): message.content = c.rstrip("\n") elif part == "f": if not message.get_form_urlencoded() and message.content: - self.master.prompt_onekey( - "Existing body is not a URL-encoded form. Clear and edit?", - [ + signals.status_prompt_onekey.send( + prompt = "Existing body is not a URL-encoded form. Clear and edit?", + keys = [ ("yes", "y"), ("no", "n"), ], - self.edit_form_confirm, - message + callback = self.edit_form_confirm, + args = (message,) ) else: self.edit_form(message) @@ -587,13 +591,29 @@ class FlowView(urwid.WidgetWrap): elif part == "q": self.master.view_grideditor(grideditor.QueryEditor(self.master, message.get_query().lst, self.set_query, message)) elif part == "u" and self.state.view_flow_mode == common.VIEW_FLOW_REQUEST: - self.master.prompt_edit("URL", message.url, self.set_url) + signals.status_prompt.send( + prompt = "URL: ", + text = message.url, + callback = self.set_url + ) elif part == "m" and self.state.view_flow_mode == common.VIEW_FLOW_REQUEST: - self.master.prompt_onekey("Method", common.METHOD_OPTIONS, self.edit_method) + signals.status_prompt_onekey.send( + prompt = "Method", + keys = common.METHOD_OPTIONS, + callback = self.edit_method + ) elif part == "c" and self.state.view_flow_mode == common.VIEW_FLOW_RESPONSE: - self.master.prompt_edit("Code", str(message.code), self.set_resp_code) + signals.status_prompt.send( + prompt = "Code: ", + text = str(message.code), + callback = self.set_resp_code + ) elif part == "m" and self.state.view_flow_mode == common.VIEW_FLOW_RESPONSE: - self.master.prompt_edit("Message", message.msg, self.set_resp_msg) + signals.status_prompt.send( + prompt = "Message: ", + text = message.msg, + callback = self.set_resp_msg + ) self.master.refresh_flow(self.flow) def _view_nextprev_flow(self, np, flow): @@ -684,9 +704,9 @@ class FlowView(urwid.WidgetWrap): signals.status_message.send(message="Duplicated.") elif key == "e": if self.state.view_flow_mode == common.VIEW_FLOW_REQUEST: - self.master.prompt_onekey( - "Edit request", - ( + signals.status_prompt_onekey.send( + prompt = "Edit request", + keys = ( ("query", "q"), ("path", "p"), ("url", "u"), @@ -695,18 +715,18 @@ class FlowView(urwid.WidgetWrap): ("raw body", "r"), ("method", "m"), ), - self.edit + callback = self.edit ) else: - self.master.prompt_onekey( - "Edit response", - ( + signals.status_prompt_onekey.send( + prompt = "Edit response", + keys = ( ("code", "c"), ("message", "m"), ("header", "h"), ("raw body", "r"), ), - self.edit + callback = self.edit ) key = None elif key == "f": @@ -727,10 +747,11 @@ class FlowView(urwid.WidgetWrap): elif key == "m": p = list(contentview.view_prompts) p.insert(0, ("Clear", "C")) - self.master.prompt_onekey( - "Display mode", - p, - self.change_this_display_mode + signals.status_prompt_onekey.send( + self, + prompt = "Display mode", + keys = p, + callback = self.change_this_display_mode ) key = None elif key == "p": @@ -748,11 +769,11 @@ class FlowView(urwid.WidgetWrap): self.master.refresh_flow(self.flow) signals.status_message.send(message="Reverted.") elif key == "W": - self.master.path_prompt( - "Save this flow: ", - self.state.last_saveload, - self.master.save_one_flow, - self.flow + signals.status_path_prompt.send( + prompt = "Save this flow: ", + text = self.state.last_saveload, + callback = self.master.save_one_flow, + args = (self.flow,) ) elif key == "v": if conn and conn.content: @@ -763,18 +784,20 @@ class FlowView(urwid.WidgetWrap): else: signals.status_message.send(message="Error! Set $EDITOR or $PAGER.") elif key == "|": - self.master.path_prompt( - "Send flow to script: ", self.state.last_script, - self.master.run_script_once, self.flow + signals.status_path_prompt.send( + prompt = "Send flow to script: ", + text = self.state.last_script, + callback = self.master.run_script_once, + args = (self.flow,) ) elif key == "x": - self.master.prompt_onekey( - "Delete body", - ( + signals.status_prompt_onekey.send( + prompt = "Delete body", + keys = ( ("completely", "c"), ("mark as missing", "m"), ), - self.delete_body + callback = self.delete_body ) key = None elif key == "X": @@ -787,22 +810,24 @@ class FlowView(urwid.WidgetWrap): if not conn.decode(): signals.status_message.send(message="Could not decode - invalid data?") else: - self.master.prompt_onekey( - "Select encoding: ", - ( + signals.status_prompt_onekey.send( + prompt = "Select encoding: ", + keys = ( ("gzip", "z"), ("deflate", "d"), ), - self.encode_callback, - conn + callback = self.encode_callback, + args = (conn,) ) self.master.refresh_flow(self.flow) elif key == "/": last_search_string = self.state.get_flow_setting(self.flow, "last_search_string") search_prompt = "Search body ["+last_search_string+"]: " if last_search_string else "Search body: " - self.master.prompt(search_prompt, - None, - self.search) + signals.status_prompt.send( + prompt = search_prompt, + text = "", + callback = self.search + ) elif key == "n": self.search_again(backwards=False) elif key == "N": -- cgit v1.2.3 From 572000aa039a789ba35d4ef14e0c096256d6997d Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Sun, 22 Mar 2015 13:59:34 +1300 Subject: Rationalise prompt calling conventions --- libmproxy/console/flowview.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'libmproxy/console/flowview.py') diff --git a/libmproxy/console/flowview.py b/libmproxy/console/flowview.py index 941ceb94..b9d5fbca 100644 --- a/libmproxy/console/flowview.py +++ b/libmproxy/console/flowview.py @@ -493,7 +493,7 @@ class FlowView(urwid.WidgetWrap): def edit_method(self, m): if m == "e": signals.status_prompt.send( - prompt = "Method: ", + prompt = "Method", text = self.flow.request.method, callback = self.set_method_raw ) @@ -592,7 +592,7 @@ class FlowView(urwid.WidgetWrap): self.master.view_grideditor(grideditor.QueryEditor(self.master, message.get_query().lst, self.set_query, message)) elif part == "u" and self.state.view_flow_mode == common.VIEW_FLOW_REQUEST: signals.status_prompt.send( - prompt = "URL: ", + prompt = "URL", text = message.url, callback = self.set_url ) @@ -604,13 +604,13 @@ class FlowView(urwid.WidgetWrap): ) elif part == "c" and self.state.view_flow_mode == common.VIEW_FLOW_RESPONSE: signals.status_prompt.send( - prompt = "Code: ", + prompt = "Code", text = str(message.code), callback = self.set_resp_code ) elif part == "m" and self.state.view_flow_mode == common.VIEW_FLOW_RESPONSE: signals.status_prompt.send( - prompt = "Message: ", + prompt = "Message", text = message.msg, callback = self.set_resp_msg ) @@ -769,8 +769,8 @@ class FlowView(urwid.WidgetWrap): self.master.refresh_flow(self.flow) signals.status_message.send(message="Reverted.") elif key == "W": - signals.status_path_prompt.send( - prompt = "Save this flow: ", + signals.status_prompt_path.send( + prompt = "Save this flow", text = self.state.last_saveload, callback = self.master.save_one_flow, args = (self.flow,) @@ -784,8 +784,8 @@ class FlowView(urwid.WidgetWrap): else: signals.status_message.send(message="Error! Set $EDITOR or $PAGER.") elif key == "|": - signals.status_path_prompt.send( - prompt = "Send flow to script: ", + signals.status_prompt_path.send( + prompt = "Send flow to script", text = self.state.last_script, callback = self.master.run_script_once, args = (self.flow,) @@ -822,7 +822,7 @@ class FlowView(urwid.WidgetWrap): self.master.refresh_flow(self.flow) elif key == "/": last_search_string = self.state.get_flow_setting(self.flow, "last_search_string") - search_prompt = "Search body ["+last_search_string+"]: " if last_search_string else "Search body: " + search_prompt = "Search body ["+last_search_string+"]" if last_search_string else "Search body" signals.status_prompt.send( prompt = search_prompt, text = "", -- cgit v1.2.3 From 200498e7aa57effd7158c8d735f95c6556203a07 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Sun, 22 Mar 2015 14:14:44 +1300 Subject: Simplify the way in which path prompts keep state In the past, we kept the last path the user specified for a number of different path types to pre-seed the path prompt. Now, we no longer distinguish between types, and pre-seed with the last used directory regardless. --- libmproxy/console/flowview.py | 2 -- 1 file changed, 2 deletions(-) (limited to 'libmproxy/console/flowview.py') diff --git a/libmproxy/console/flowview.py b/libmproxy/console/flowview.py index b9d5fbca..d63b8a8c 100644 --- a/libmproxy/console/flowview.py +++ b/libmproxy/console/flowview.py @@ -771,7 +771,6 @@ class FlowView(urwid.WidgetWrap): elif key == "W": signals.status_prompt_path.send( prompt = "Save this flow", - text = self.state.last_saveload, callback = self.master.save_one_flow, args = (self.flow,) ) @@ -786,7 +785,6 @@ class FlowView(urwid.WidgetWrap): elif key == "|": signals.status_prompt_path.send( prompt = "Send flow to script", - text = self.state.last_script, callback = self.master.run_script_once, args = (self.flow,) ) -- cgit v1.2.3 From aa9a38522f5fbfef556578b6018ad365ad5e844d Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Sun, 22 Mar 2015 15:58:32 +1300 Subject: Remove refresh_flow mechanism in favor of a signal-based implementation --- libmproxy/console/flowview.py | 60 ++++++++++++++++++++++++------------------- 1 file changed, 33 insertions(+), 27 deletions(-) (limited to 'libmproxy/console/flowview.py') diff --git a/libmproxy/console/flowview.py b/libmproxy/console/flowview.py index d63b8a8c..2dd2cb82 100644 --- a/libmproxy/console/flowview.py +++ b/libmproxy/console/flowview.py @@ -88,10 +88,17 @@ class FlowViewHeader(urwid.WidgetWrap): def __init__(self, master, f): self.master, self.flow = master, f self._w = common.format_flow(f, False, extended=True, padding=0, hostheader=self.master.showhost) - - def refresh_flow(self, f): - if f == self.flow: - self._w = common.format_flow(f, False, extended=True, padding=0, hostheader=self.master.showhost) + signals.flow_change.connect(self.sig_flow_change) + + def sig_flow_change(self, sender, flow): + if flow == self.flow: + self._w = common.format_flow( + flow, + False, + extended=True, + padding=0, + hostheader=self.master.showhost + ) class CallbackCache: @@ -119,6 +126,14 @@ class FlowView(urwid.WidgetWrap): self.view_response() else: self.view_request() + signals.flow_change.connect(self.sig_flow_change) + + def sig_flow_change(self, sender, flow): + if flow == self.flow: + if self.state.view_flow_mode == common.VIEW_FLOW_RESPONSE and self.flow.response: + self.view_response() + else: + self.view_request() def _cached_content_view(self, viewmode, hdrItems, content, limit, is_request): return contentview.get_content_view(viewmode, hdrItems, content, limit, self.master.add_event, is_request) @@ -332,7 +347,7 @@ class FlowView(urwid.WidgetWrap): list_box = urwid.ListBox(merged) list_box.set_focus(focus_position + 2) self._w = self.wrap_body(const, list_box) - self.master.statusbar.redraw() + signals.update_settings.send(self) self.last_displayed_body = list_box @@ -456,7 +471,6 @@ class FlowView(urwid.WidgetWrap): self.state.view_flow_mode = common.VIEW_FLOW_REQUEST body = self.conn_text(self.flow.request) self._w = self.wrap_body(common.VIEW_FLOW_REQUEST, body) - self.master.statusbar.redraw() def view_response(self): self.state.view_flow_mode = common.VIEW_FLOW_RESPONSE @@ -476,19 +490,11 @@ class FlowView(urwid.WidgetWrap): ] ) self._w = self.wrap_body(common.VIEW_FLOW_RESPONSE, body) - self.master.statusbar.redraw() - - def refresh_flow(self, c=None): - if c == self.flow: - if self.state.view_flow_mode == common.VIEW_FLOW_RESPONSE and self.flow.response: - self.view_response() - else: - self.view_request() def set_method_raw(self, m): if m: self.flow.request.method = m - self.master.refresh_flow(self.flow) + signals.flow_change.send(self, flow = self.flow) def edit_method(self, m): if m == "e": @@ -501,7 +507,7 @@ class FlowView(urwid.WidgetWrap): for i in common.METHOD_OPTIONS: if i[1] == m: self.flow.request.method = i[0].upper() - self.master.refresh_flow(self.flow) + signals.flow_change.send(self, flow = self.flow) def set_url(self, url): request = self.flow.request @@ -509,7 +515,7 @@ class FlowView(urwid.WidgetWrap): request.url = str(url) except ValueError: return "Invalid URL." - self.master.refresh_flow(self.flow) + signals.flow_change.send(self, flow = self.flow) def set_resp_code(self, code): response = self.flow.response @@ -520,12 +526,12 @@ class FlowView(urwid.WidgetWrap): import BaseHTTPServer if BaseHTTPServer.BaseHTTPRequestHandler.responses.has_key(int(code)): response.msg = BaseHTTPServer.BaseHTTPRequestHandler.responses[int(code)][0] - self.master.refresh_flow(self.flow) + signals.flow_change.send(self, flow = self.flow) def set_resp_msg(self, msg): response = self.flow.response response.msg = msg - self.master.refresh_flow(self.flow) + signals.flow_change.send(self, flow = self.flow) def set_headers(self, lst, conn): conn.headers = flow.ODictCaseless(lst) @@ -614,7 +620,7 @@ class FlowView(urwid.WidgetWrap): text = message.msg, callback = self.set_resp_msg ) - self.master.refresh_flow(self.flow) + signals.flow_change.send(self, flow = self.flow) def _view_nextprev_flow(self, np, flow): try: @@ -642,7 +648,7 @@ class FlowView(urwid.WidgetWrap): (self.state.view_flow_mode, "prettyview"), contentview.get_by_shortcut(t) ) - self.master.refresh_flow(self.flow) + signals.flow_change.send(self, flow = self.flow) def delete_body(self, t): if t == "m": @@ -653,7 +659,7 @@ class FlowView(urwid.WidgetWrap): self.flow.request.content = val else: self.flow.response.content = val - self.master.refresh_flow(self.flow) + signals.flow_change.send(self, flow = self.flow) def keypress(self, size, key): if key == " ": @@ -736,7 +742,7 @@ class FlowView(urwid.WidgetWrap): (self.state.view_flow_mode, "fullcontents"), True ) - self.master.refresh_flow(self.flow) + signals.flow_change.send(self, flow = self.flow) signals.status_message.send(message="") elif key == "g": if self.state.view_flow_mode == common.VIEW_FLOW_REQUEST: @@ -760,13 +766,13 @@ class FlowView(urwid.WidgetWrap): r = self.master.replay_request(self.flow) if r: signals.status_message.send(message=r) - self.master.refresh_flow(self.flow) + signals.flow_change.send(self, flow = self.flow) elif key == "V": if not self.flow.modified(): signals.status_message.send(message="Flow not modified.") return self.state.revert(self.flow) - self.master.refresh_flow(self.flow) + signals.flow_change.send(self, flow = self.flow) signals.status_message.send(message="Reverted.") elif key == "W": signals.status_prompt_path.send( @@ -817,7 +823,7 @@ class FlowView(urwid.WidgetWrap): callback = self.encode_callback, args = (conn,) ) - self.master.refresh_flow(self.flow) + signals.flow_change.send(self, flow = self.flow) elif key == "/": last_search_string = self.state.get_flow_setting(self.flow, "last_search_string") search_prompt = "Search body ["+last_search_string+"]" if last_search_string else "Search body" @@ -839,4 +845,4 @@ class FlowView(urwid.WidgetWrap): "d": "deflate", } conn.encode(encoding_map[key]) - self.master.refresh_flow(self.flow) + signals.flow_change.send(self, flow = self.flow) -- cgit v1.2.3 From 08bb07653306ed0f84932391732391227ee07ba2 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Sun, 22 Mar 2015 17:18:53 +1300 Subject: console: signal-based view stack, unifying mechanisms for help, flow views, etc. --- libmproxy/console/flowview.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'libmproxy/console/flowview.py') diff --git a/libmproxy/console/flowview.py b/libmproxy/console/flowview.py index 2dd2cb82..fcb967cc 100644 --- a/libmproxy/console/flowview.py +++ b/libmproxy/console/flowview.py @@ -114,9 +114,6 @@ cache = CallbackCache() class FlowView(urwid.WidgetWrap): - REQ = 0 - RESP = 1 - highlight_color = "focusfield" def __init__(self, master, state, flow): @@ -633,8 +630,9 @@ class FlowView(urwid.WidgetWrap): new_flow, new_idx = self.state.get_prev(idx) if new_flow is None: signals.status_message.send(message="No more flows!") - return - self.master.view_flow(new_flow) + else: + signals.pop_view_state.send(self) + self.master.view_flow(new_flow) def view_next_flow(self, flow): return self._view_nextprev_flow("next", flow) @@ -673,8 +671,8 @@ class FlowView(urwid.WidgetWrap): conn = self.flow.response if key == "q": - self.master.view_flowlist() - key = None + signals.pop_view_state.send(self) + return None elif key == "tab": if self.state.view_flow_mode == common.VIEW_FLOW_REQUEST: self.view_response() -- cgit v1.2.3 From 15f65d63f633b6b6a540f74006efe542796aa7e4 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Sun, 22 Mar 2015 17:28:13 +1300 Subject: Trigger flow change when flow elements are edited --- libmproxy/console/flowview.py | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) (limited to 'libmproxy/console/flowview.py') diff --git a/libmproxy/console/flowview.py b/libmproxy/console/flowview.py index fcb967cc..04440888 100644 --- a/libmproxy/console/flowview.py +++ b/libmproxy/console/flowview.py @@ -532,19 +532,28 @@ class FlowView(urwid.WidgetWrap): def set_headers(self, lst, conn): conn.headers = flow.ODictCaseless(lst) + signals.flow_change.send(self, flow = self.flow) def set_query(self, lst, conn): conn.set_query(flow.ODict(lst)) + signals.flow_change.send(self, flow = self.flow) def set_path_components(self, lst, conn): conn.set_path_components([i[0] for i in lst]) + signals.flow_change.send(self, flow = self.flow) def set_form(self, lst, conn): conn.set_form_urlencoded(flow.ODict(lst)) + signals.flow_change.send(self, flow = self.flow) def edit_form(self, conn): self.master.view_grideditor( - grideditor.URLEncodedFormEditor(self.master, conn.get_form_urlencoded().lst, self.set_form, conn) + grideditor.URLEncodedFormEditor( + self.master, + conn.get_form_urlencoded().lst, + self.set_form, + conn + ) ) def edit_form_confirm(self, key, conn): @@ -586,7 +595,14 @@ class FlowView(urwid.WidgetWrap): else: self.edit_form(message) elif part == "h": - self.master.view_grideditor(grideditor.HeaderEditor(self.master, message.headers.lst, self.set_headers, message)) + self.master.view_grideditor( + grideditor.HeaderEditor( + self.master, + message.headers.lst, + self.set_headers, + message + ) + ) elif part == "p": p = message.get_path_components() p = [[i] for i in p] -- cgit v1.2.3 From a2da38cc8339887abef4efa23cc54fa02c981f3f Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Sun, 22 Mar 2015 17:33:25 +1300 Subject: Whitespace, indentation, formatting --- libmproxy/console/flowview.py | 128 +++++++++++++++++++++++++++++++++--------- 1 file changed, 102 insertions(+), 26 deletions(-) (limited to 'libmproxy/console/flowview.py') diff --git a/libmproxy/console/flowview.py b/libmproxy/console/flowview.py index 04440888..e864cf47 100644 --- a/libmproxy/console/flowview.py +++ b/libmproxy/console/flowview.py @@ -87,7 +87,13 @@ footer = [ class FlowViewHeader(urwid.WidgetWrap): def __init__(self, master, f): self.master, self.flow = master, f - self._w = common.format_flow(f, False, extended=True, padding=0, hostheader=self.master.showhost) + self._w = common.format_flow( + f, + False, + extended=True, + padding=0, + hostheader=self.master.showhost + ) signals.flow_change.connect(self.sig_flow_change) def sig_flow_change(self, sender, flow): @@ -133,7 +139,14 @@ class FlowView(urwid.WidgetWrap): self.view_request() def _cached_content_view(self, viewmode, hdrItems, content, limit, is_request): - return contentview.get_content_view(viewmode, hdrItems, content, limit, self.master.add_event, is_request) + return contentview.get_content_view( + viewmode, + hdrItems, + content, + limit, + self.master.add_event, + is_request + ) def content_view(self, viewmode, conn): full = self.state.get_flow_setting( @@ -219,7 +232,8 @@ class FlowView(urwid.WidgetWrap): def conn_text(self, conn): """ - Same as conn_text_raw, but returns result wrapped in a listbox ready for usage. + Same as conn_text_raw, but returns result wrapped in a listbox ready for + usage. """ headers, msg, body = self.conn_text_raw(conn) merged = self.conn_text_merge(headers, msg, body) @@ -290,7 +304,9 @@ class FlowView(urwid.WidgetWrap): """ runs the previous search again, forwards or backwards. """ - last_search_string = self.state.get_flow_setting(self.flow, "last_search_string") + last_search_string = self.state.get_flow_setting( + self.flow, "last_search_string" + ) if last_search_string: message = self.search(last_search_string, backwards) if message: @@ -331,7 +347,11 @@ class FlowView(urwid.WidgetWrap): # generate the body, highlight the words and get focus headers, msg, body = self.conn_text_raw(text) try: - body, focus_position = self.search_highlight_text(body, search_string, backwards=backwards) + body, focus_position = self.search_highlight_text( + body, + search_string, + backwards=backwards + ) except SearchError: return "Search not supported in this view." @@ -348,7 +368,11 @@ class FlowView(urwid.WidgetWrap): self.last_displayed_body = list_box - wrapped, wrapped_message = self.search_wrapped_around(last_find_line, last_search_index, backwards) + wrapped, wrapped_message = self.search_wrapped_around( + last_find_line, + last_search_index, + backwards + ) if wrapped: return wrapped_message @@ -356,9 +380,15 @@ class FlowView(urwid.WidgetWrap): def search_get_start(self, search_string): start_line = 0 start_index = 0 - last_search_string = self.state.get_flow_setting(self.flow, "last_search_string") + last_search_string = self.state.get_flow_setting( + self.flow, + "last_search_string" + ) if search_string == last_search_string: - start_line = self.state.get_flow_setting(self.flow, "last_find_line") + start_line = self.state.get_flow_setting( + self.flow, + "last_find_line" + ) start_index = self.state.get_flow_setting(self.flow, "last_search_index") @@ -403,7 +433,10 @@ class FlowView(urwid.WidgetWrap): found = False text_objects = copy.deepcopy(text_objects) - loop_range = self.search_get_range(len(text_objects), start_line, backwards) + loop_range = self.search_get_range( + len(text_objects), + start_line, backwards + ) for i in loop_range: text_object = text_objects[i] @@ -415,10 +448,19 @@ class FlowView(urwid.WidgetWrap): if i != start_line: start_index = 0 - find_index = self.search_find(text, search_string, start_index, backwards) + find_index = self.search_find( + text, + search_string, + start_index, + backwards + ) if find_index != -1: - new_text = self.search_highlight_object(text, find_index, search_string) + new_text = self.search_highlight_object( + text, + find_index, + search_string + ) text_objects[i] = new_text found = True @@ -436,14 +478,26 @@ class FlowView(urwid.WidgetWrap): focus_pos = None else: if not backwards: - self.state.add_flow_setting(self.flow, "last_search_index", 0) - self.state.add_flow_setting(self.flow, "last_find_line", 0) + self.state.add_flow_setting( + self.flow, "last_search_index", 0 + ) + self.state.add_flow_setting( + self.flow, "last_find_line", 0 + ) else: - self.state.add_flow_setting(self.flow, "last_search_index", None) - self.state.add_flow_setting(self.flow, "last_find_line", len(text_objects) - 1) + self.state.add_flow_setting( + self.flow, "last_search_index", None + ) + self.state.add_flow_setting( + self.flow, "last_find_line", len(text_objects) - 1 + ) - text_objects, focus_pos = self.search_highlight_text(text_objects, - search_string, looping=True, backwards=backwards) + text_objects, focus_pos = self.search_highlight_text( + text_objects, + search_string, + looping=True, + backwards=backwards + ) return text_objects, focus_pos @@ -575,10 +629,12 @@ class FlowView(urwid.WidgetWrap): self.flow.backup() if part == "r": with decoded(message): - # Fix an issue caused by some editors when editing a request/response body. - # Many editors make it hard to save a file without a terminating newline on the last - # line. When editing message bodies, this can cause problems. For now, I just - # strip the newlines off the end of the body when we return from an editor. + # Fix an issue caused by some editors when editing a + # request/response body. Many editors make it hard to save a + # file without a terminating newline on the last line. When + # editing message bodies, this can cause problems. For now, I + # just strip the newlines off the end of the body when we return + # from an editor. c = self.master.spawn_editor(message.content or "") message.content = c.rstrip("\n") elif part == "f": @@ -606,9 +662,22 @@ class FlowView(urwid.WidgetWrap): elif part == "p": p = message.get_path_components() p = [[i] for i in p] - self.master.view_grideditor(grideditor.PathEditor(self.master, p, self.set_path_components, message)) + self.master.view_grideditor( + grideditor.PathEditor( + self.master, + p, + self.set_path_components, + message + ) + ) elif part == "q": - self.master.view_grideditor(grideditor.QueryEditor(self.master, message.get_query().lst, self.set_query, message)) + self.master.view_grideditor( + grideditor.QueryEditor( + self.master, + message.get_query().lst, + self.set_query, message + ) + ) elif part == "u" and self.state.view_flow_mode == common.VIEW_FLOW_REQUEST: signals.status_prompt.send( prompt = "URL", @@ -801,7 +870,9 @@ class FlowView(urwid.WidgetWrap): if os.environ.has_key("EDITOR") or os.environ.has_key("PAGER"): self.master.spawn_external_viewer(conn.content, t) else: - signals.status_message.send(message="Error! Set $EDITOR or $PAGER.") + signals.status_message.send( + message = "Error! Set $EDITOR or $PAGER." + ) elif key == "|": signals.status_prompt_path.send( prompt = "Send flow to script", @@ -826,7 +897,9 @@ class FlowView(urwid.WidgetWrap): e = conn.headers.get_first("content-encoding", "identity") if e != "identity": if not conn.decode(): - signals.status_message.send(message="Could not decode - invalid data?") + signals.status_message.send( + message = "Could not decode - invalid data?" + ) else: signals.status_prompt_onekey.send( prompt = "Select encoding: ", @@ -839,7 +912,10 @@ class FlowView(urwid.WidgetWrap): ) signals.flow_change.send(self, flow = self.flow) elif key == "/": - last_search_string = self.state.get_flow_setting(self.flow, "last_search_string") + last_search_string = self.state.get_flow_setting( + self.flow, + "last_search_string" + ) search_prompt = "Search body ["+last_search_string+"]" if last_search_string else "Search body" signals.status_prompt.send( prompt = search_prompt, -- cgit v1.2.3 From 842e23d3e386169d9a90cef2a634c55a3e5fdd8e Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Sun, 22 Mar 2015 21:00:41 +1300 Subject: Replace far-too-clever decorator LRU cache with something simpler --- libmproxy/console/flowview.py | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) (limited to 'libmproxy/console/flowview.py') diff --git a/libmproxy/console/flowview.py b/libmproxy/console/flowview.py index e864cf47..2c847fba 100644 --- a/libmproxy/console/flowview.py +++ b/libmproxy/console/flowview.py @@ -107,16 +107,7 @@ class FlowViewHeader(urwid.WidgetWrap): ) -class CallbackCache: - @utils.LRUCache(200) - def _callback(self, method, *args, **kwargs): - return getattr(self.obj, method)(*args, **kwargs) - - def callback(self, obj, method, *args, **kwargs): - # obj varies! - self.obj = obj - return self._callback(method, *args, **kwargs) -cache = CallbackCache() +cache = utils.LRUCache(200) class FlowView(urwid.WidgetWrap): @@ -158,8 +149,8 @@ class FlowView(urwid.WidgetWrap): limit = sys.maxint else: limit = contentview.VIEW_CUTOFF - description, text_objects = cache.callback( - self, "_cached_content_view", + description, text_objects = cache.get( + self._cached_content_view, viewmode, tuple(tuple(i) for i in conn.headers.lst), conn.content, -- cgit v1.2.3 From 6fb661dab518c036e9333d360f2efc91bc2631ab Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Sun, 22 Mar 2015 21:08:18 +1300 Subject: Unwind twisty maze of cache layers. Holy confusing, Batman. --- libmproxy/console/flowview.py | 57 +++++++++++++++++-------------------------- 1 file changed, 22 insertions(+), 35 deletions(-) (limited to 'libmproxy/console/flowview.py') diff --git a/libmproxy/console/flowview.py b/libmproxy/console/flowview.py index 2c847fba..1aebb0f0 100644 --- a/libmproxy/console/flowview.py +++ b/libmproxy/console/flowview.py @@ -129,43 +129,30 @@ class FlowView(urwid.WidgetWrap): else: self.view_request() - def _cached_content_view(self, viewmode, hdrItems, content, limit, is_request): - return contentview.get_content_view( - viewmode, - hdrItems, - content, - limit, - self.master.add_event, - is_request - ) - 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 + if conn.content == CONTENT_MISSING: + msg, body = "", [urwid.Text([("error", "[content missing]")])] + return (msg, body) else: - limit = contentview.VIEW_CUTOFF - description, text_objects = cache.get( - self._cached_content_view, - viewmode, - tuple(tuple(i) for i in conn.headers.lst), - conn.content, - limit, - isinstance(conn, HTTPRequest) - ) - return (description, text_objects) - - def cont_view_handle_missing(self, conn, viewmode): - if conn.content == CONTENT_MISSING: - msg, body = "", [urwid.Text([("error", "[content missing]")])] + full = self.state.get_flow_setting( + self.flow, + (self.state.view_flow_mode, "fullcontents"), + False + ) + if full: + limit = sys.maxint else: - msg, body = self.content_view(viewmode, conn) - - return (msg, body) + limit = contentview.VIEW_CUTOFF + description, text_objects = cache.get( + contentview.get_content_view, + viewmode, + tuple(tuple(i) for i in conn.headers.lst), + conn.content, + limit, + self.master.add_event, + isinstance(conn, HTTPRequest) + ) + return (description, text_objects) def viewmode_get(self, override): return self.state.default_body_view if override is None else override @@ -186,7 +173,7 @@ class FlowView(urwid.WidgetWrap): ) override = self.override_get() viewmode = self.viewmode_get(override) - msg, body = self.cont_view_handle_missing(conn, viewmode) + msg, body = self.content_view(viewmode, conn) return headers, msg, body def conn_text_merge(self, headers, msg, body): -- cgit v1.2.3 From 8a0404ddf81a61642e516dd32025ba54d7d3676f Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Sun, 29 Mar 2015 14:32:36 +1300 Subject: Beginning of a simpler and more flexible search implementation --- libmproxy/console/flowview.py | 270 +----------------------------------------- 1 file changed, 5 insertions(+), 265 deletions(-) (limited to 'libmproxy/console/flowview.py') diff --git a/libmproxy/console/flowview.py b/libmproxy/console/flowview.py index 1aebb0f0..a431d65f 100644 --- a/libmproxy/console/flowview.py +++ b/libmproxy/console/flowview.py @@ -1,7 +1,7 @@ from __future__ import absolute_import import os, sys, copy import urwid -from . import common, grideditor, contentview, signals +from . import common, grideditor, contentview, signals, searchable from .. import utils, flow, controller from ..protocol.http import HTTPRequest, HTTPResponse, CONTENT_MISSING, decoded @@ -179,7 +179,7 @@ class FlowView(urwid.WidgetWrap): def conn_text_merge(self, headers, msg, body): """ Grabs what is returned by conn_text_raw and merges them all - toghether, mainly used by conn_text and search + toghether, mainly used by conn_text """ override = self.override_get() viewmode = self.viewmode_get(override) @@ -215,7 +215,7 @@ class FlowView(urwid.WidgetWrap): """ headers, msg, body = self.conn_text_raw(conn) merged = self.conn_text_merge(headers, msg, body) - return urwid.ListBox(merged) + return searchable.Searchable(merged) def _tab(self, content, attr): p = urwid.Text(content) @@ -251,251 +251,6 @@ class FlowView(urwid.WidgetWrap): ) return f - def search_wrapped_around(self, last_find_line, last_search_index, backwards): - """ - returns true if search wrapped around the bottom. - """ - - current_find_line = self.state.get_flow_setting(self.flow, - "last_find_line") - current_search_index = self.state.get_flow_setting(self.flow, - "last_search_index") - - if not backwards: - message = "search hit BOTTOM, continuing at TOP" - if current_find_line <= last_find_line: - return True, message - elif current_find_line == last_find_line: - if current_search_index <= last_search_index: - return True, message - else: - message = "search hit TOP, continuing at BOTTOM" - if current_find_line >= last_find_line: - return True, message - elif current_find_line == last_find_line: - if current_search_index >= last_search_index: - return True, message - - return False, "" - - def search_again(self, backwards=False): - """ - runs the previous search again, forwards or backwards. - """ - last_search_string = self.state.get_flow_setting( - self.flow, "last_search_string" - ) - if last_search_string: - message = self.search(last_search_string, backwards) - if message: - signals.status_message.send(message=message) - else: - message = "no previous searches have been made" - signals.status_message.send(message=message) - - return message - - def search(self, search_string, backwards=False): - """ - similar to view_response or view_request, but instead of just - displaying the conn, it highlights a word that the user is - searching for and handles all the logic surrounding that. - """ - - if not search_string: - search_string = self.state.get_flow_setting(self.flow, - "last_search_string") - if not search_string: - return - - if self.state.view_flow_mode == common.VIEW_FLOW_REQUEST: - text = self.flow.request - const = common.VIEW_FLOW_REQUEST - else: - text = self.flow.response - const = common.VIEW_FLOW_RESPONSE - if not self.flow.response: - return "no response to search in" - - last_find_line = self.state.get_flow_setting(self.flow, - "last_find_line") - last_search_index = self.state.get_flow_setting(self.flow, - "last_search_index") - - # generate the body, highlight the words and get focus - headers, msg, body = self.conn_text_raw(text) - try: - body, focus_position = self.search_highlight_text( - body, - search_string, - backwards=backwards - ) - except SearchError: - return "Search not supported in this view." - - if focus_position == None: - # no results found. - return "no matches for '%s'" % search_string - - # UI stuff. - merged = self.conn_text_merge(headers, msg, body) - list_box = urwid.ListBox(merged) - list_box.set_focus(focus_position + 2) - self._w = self.wrap_body(const, list_box) - signals.update_settings.send(self) - - self.last_displayed_body = list_box - - wrapped, wrapped_message = self.search_wrapped_around( - last_find_line, - last_search_index, - backwards - ) - - if wrapped: - return wrapped_message - - def search_get_start(self, search_string): - start_line = 0 - start_index = 0 - last_search_string = self.state.get_flow_setting( - self.flow, - "last_search_string" - ) - if search_string == last_search_string: - start_line = self.state.get_flow_setting( - self.flow, - "last_find_line" - ) - start_index = self.state.get_flow_setting(self.flow, - "last_search_index") - - if start_index == None: - start_index = 0 - else: - start_index += len(search_string) - - if start_line == None: - start_line = 0 - - else: - self.state.add_flow_setting(self.flow, "last_search_string", - search_string) - - return (start_line, start_index) - - def search_get_range(self, len_text_objects, start_line, backwards): - if not backwards: - loop_range = xrange(start_line, len_text_objects) - else: - loop_range = xrange(start_line, -1, -1) - - return loop_range - - def search_find(self, text, search_string, start_index, backwards): - if backwards == False: - find_index = text.find(search_string, start_index) - else: - if start_index != 0: - start_index -= len(search_string) - else: - start_index = None - - find_index = text.rfind(search_string, 0, start_index) - - return find_index - - def search_highlight_text(self, text_objects, search_string, looping = False, backwards = False): - start_line, start_index = self.search_get_start(search_string) - i = start_line - - found = False - text_objects = copy.deepcopy(text_objects) - loop_range = self.search_get_range( - len(text_objects), - start_line, backwards - ) - for i in loop_range: - text_object = text_objects[i] - - try: - text, style = text_object.get_text() - except AttributeError: - raise SearchError() - - if i != start_line: - start_index = 0 - - find_index = self.search_find( - text, - search_string, - start_index, - backwards - ) - - if find_index != -1: - new_text = self.search_highlight_object( - text, - find_index, - search_string - ) - text_objects[i] = new_text - - found = True - self.state.add_flow_setting(self.flow, "last_search_index", - find_index) - self.state.add_flow_setting(self.flow, "last_find_line", i) - - break - - # handle search WRAP - if found: - focus_pos = i - else : - if looping: - focus_pos = None - else: - if not backwards: - self.state.add_flow_setting( - self.flow, "last_search_index", 0 - ) - self.state.add_flow_setting( - self.flow, "last_find_line", 0 - ) - else: - self.state.add_flow_setting( - self.flow, "last_search_index", None - ) - self.state.add_flow_setting( - self.flow, "last_find_line", len(text_objects) - 1 - ) - - text_objects, focus_pos = self.search_highlight_text( - text_objects, - search_string, - looping=True, - backwards=backwards - ) - - return text_objects, focus_pos - - def search_highlight_object(self, text_object, find_index, search_string): - """ - just a little abstraction - """ - before = text_object[:find_index] - after = text_object[find_index+len(search_string):] - - new_text = urwid.Text( - [ - before, - (self.highlight_color, search_string), - after, - ] - ) - - return new_text - def view_request(self): self.state.view_flow_mode = common.VIEW_FLOW_REQUEST body = self.conn_text(self.flow.request) @@ -506,7 +261,7 @@ class FlowView(urwid.WidgetWrap): if self.flow.response: body = self.conn_text(self.flow.response) else: - body = urwid.ListBox( + body = searchable.Searchable( [ urwid.Text(""), urwid.Text( @@ -889,23 +644,8 @@ class FlowView(urwid.WidgetWrap): args = (conn,) ) signals.flow_change.send(self, flow = self.flow) - elif key == "/": - last_search_string = self.state.get_flow_setting( - self.flow, - "last_search_string" - ) - search_prompt = "Search body ["+last_search_string+"]" if last_search_string else "Search body" - signals.status_prompt.send( - prompt = search_prompt, - text = "", - callback = self.search - ) - elif key == "n": - self.search_again(backwards=False) - elif key == "N": - self.search_again(backwards=True) else: - return key + return super(self.__class__, self).keypress(size, key) def encode_callback(self, key, conn): encoding_map = { -- cgit v1.2.3 From 80c4de5ca462a211fca33d45fe52441b246d4d03 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Sun, 29 Mar 2015 15:14:56 +1300 Subject: Keep record of last search term --- libmproxy/console/flowview.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'libmproxy/console/flowview.py') diff --git a/libmproxy/console/flowview.py b/libmproxy/console/flowview.py index a431d65f..c38b9fea 100644 --- a/libmproxy/console/flowview.py +++ b/libmproxy/console/flowview.py @@ -215,7 +215,7 @@ class FlowView(urwid.WidgetWrap): """ headers, msg, body = self.conn_text_raw(conn) merged = self.conn_text_merge(headers, msg, body) - return searchable.Searchable(merged) + return searchable.Searchable(self.state, merged) def _tab(self, content, attr): p = urwid.Text(content) @@ -262,6 +262,7 @@ class FlowView(urwid.WidgetWrap): body = self.conn_text(self.flow.response) else: body = searchable.Searchable( + self.state, [ urwid.Text(""), urwid.Text( -- cgit v1.2.3 From 8f0e4a9bdd29d75ff451002f933d86a09f63dbc8 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Sun, 29 Mar 2015 15:27:17 +1300 Subject: console: simplify view modes. --- libmproxy/console/flowview.py | 35 +++++++++++++++-------------------- 1 file changed, 15 insertions(+), 20 deletions(-) (limited to 'libmproxy/console/flowview.py') diff --git a/libmproxy/console/flowview.py b/libmproxy/console/flowview.py index c38b9fea..d4bdb458 100644 --- a/libmproxy/console/flowview.py +++ b/libmproxy/console/flowview.py @@ -154,13 +154,13 @@ class FlowView(urwid.WidgetWrap): ) return (description, text_objects) - def viewmode_get(self, override): + def viewmode_get(self): + override = self.state.get_flow_setting( + self.flow, + (self.state.view_flow_mode, "prettyview") + ) return self.state.default_body_view if override is None else override - def override_get(self): - return self.state.get_flow_setting(self.flow, - (self.state.view_flow_mode, "prettyview")) - def conn_text_raw(self, conn): """ Based on a request/response, conn, returns the elements for @@ -171,8 +171,7 @@ class FlowView(urwid.WidgetWrap): key = "header", val = "text" ) - override = self.override_get() - viewmode = self.viewmode_get(override) + viewmode = self.viewmode_get() msg, body = self.content_view(viewmode, conn) return headers, msg, body @@ -181,26 +180,22 @@ class FlowView(urwid.WidgetWrap): Grabs what is returned by conn_text_raw and merges them all toghether, mainly used by conn_text """ - override = self.override_get() - viewmode = self.viewmode_get(override) - + viewmode = self.viewmode_get() cols = [urwid.Text( [ ("heading", msg), ] ) ] - - if override is not None: - cols.append(urwid.Text([ - " ", - ('heading', "["), - ('heading_key', "m"), - ('heading', (":%s]"%viewmode.name)), - ], - align="right" - ) + cols.append(urwid.Text([ + " ", + ('heading', "["), + ('heading_key', "m"), + ('heading', (":%s]"%viewmode.name)), + ], + align="right" ) + ) title = urwid.AttrWrap(urwid.Columns(cols), "heading") headers.append(title) -- cgit v1.2.3 From cfeee347d95cf56dfaf53c77ac5726bb72347234 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Sun, 29 Mar 2015 15:54:29 +1300 Subject: Simplify content generation in flow view --- libmproxy/console/flowview.py | 104 ++++++++++++++++-------------------------- 1 file changed, 40 insertions(+), 64 deletions(-) (limited to 'libmproxy/console/flowview.py') diff --git a/libmproxy/console/flowview.py b/libmproxy/console/flowview.py index d4bdb458..a7a47694 100644 --- a/libmproxy/console/flowview.py +++ b/libmproxy/console/flowview.py @@ -161,56 +161,47 @@ class FlowView(urwid.WidgetWrap): ) return self.state.default_body_view if override is None else override - def conn_text_raw(self, conn): - """ - Based on a request/response, conn, returns the elements for - display. - """ - headers = common.format_keyvals( - [(h+":", v) for (h, v) in conn.headers.lst], - key = "header", - val = "text" - ) - viewmode = self.viewmode_get() - msg, body = self.content_view(viewmode, conn) - return headers, msg, body - - def conn_text_merge(self, headers, msg, body): - """ - Grabs what is returned by conn_text_raw and merges them all - toghether, mainly used by conn_text - """ - viewmode = self.viewmode_get() - cols = [urwid.Text( - [ - ("heading", msg), - ] - ) - ] - cols.append(urwid.Text([ - " ", - ('heading', "["), - ('heading_key', "m"), - ('heading', (":%s]"%viewmode.name)), - ], - align="right" - ) - ) - - title = urwid.AttrWrap(urwid.Columns(cols), "heading") - headers.append(title) - headers.extend(body) + def conn_text(self, conn): + if conn: + txt = common.format_keyvals( + [(h+":", v) for (h, v) in conn.headers.lst], + key = "header", + val = "text" + ) + viewmode = self.viewmode_get() + msg, body = self.content_view(viewmode, conn) - return headers + cols = [urwid.Text( + [ + ("heading", msg), + ] + ) + ] + cols.append(urwid.Text([ + " ", + ('heading', "["), + ('heading_key', "m"), + ('heading', (":%s]"%viewmode.name)), + ], + align="right" + ) + ) + title = urwid.AttrWrap(urwid.Columns(cols), "heading") - def conn_text(self, conn): - """ - Same as conn_text_raw, but returns result wrapped in a listbox ready for - usage. - """ - headers, msg, body = self.conn_text_raw(conn) - merged = self.conn_text_merge(headers, msg, body) - return searchable.Searchable(self.state, merged) + txt.append(title) + txt.extend(body) + else: + txt = [ + urwid.Text(""), + urwid.Text( + [ + ("highlight", "No response. Press "), + ("key", "e"), + ("highlight", " and edit any aspect to add one."), + ] + ) + ] + return searchable.Searchable(self.state, txt) def _tab(self, content, attr): p = urwid.Text(content) @@ -253,22 +244,7 @@ class FlowView(urwid.WidgetWrap): def view_response(self): self.state.view_flow_mode = common.VIEW_FLOW_RESPONSE - if self.flow.response: - body = self.conn_text(self.flow.response) - else: - body = searchable.Searchable( - self.state, - [ - urwid.Text(""), - urwid.Text( - [ - ("highlight", "No response. Press "), - ("key", "e"), - ("highlight", " and edit any aspect to add one."), - ] - ) - ] - ) + body = self.conn_text(self.flow.response) self._w = self.wrap_body(common.VIEW_FLOW_RESPONSE, body) def set_method_raw(self, m): -- cgit v1.2.3 From cacd09fafc19b323c46c4c565d0044593b677e17 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Sun, 29 Mar 2015 17:40:43 +1300 Subject: console: add a tabs widget, and use it for flowview. --- libmproxy/console/flowview.py | 124 +++++++++++++++++------------------------- 1 file changed, 49 insertions(+), 75 deletions(-) (limited to 'libmproxy/console/flowview.py') diff --git a/libmproxy/console/flowview.py b/libmproxy/console/flowview.py index a7a47694..ffe499d7 100644 --- a/libmproxy/console/flowview.py +++ b/libmproxy/console/flowview.py @@ -1,7 +1,7 @@ from __future__ import absolute_import import os, sys, copy import urwid -from . import common, grideditor, contentview, signals, searchable +from . import common, grideditor, contentview, signals, searchable, tabs from .. import utils, flow, controller from ..protocol.http import HTTPRequest, HTTPResponse, CONTENT_MISSING, decoded @@ -109,25 +109,48 @@ class FlowViewHeader(urwid.WidgetWrap): cache = utils.LRUCache(200) +TAB_REQ = 0 +TAB_RESP = 1 -class FlowView(urwid.WidgetWrap): +class FlowView(tabs.Tabs): highlight_color = "focusfield" - def __init__(self, master, state, flow): + def __init__(self, master, state, flow, tab_offset): self.master, self.state, self.flow = master, state, flow + tabs.Tabs.__init__(self, + [ + (self.tab_request, self.view_request), + (self.tab_response, self.view_response), + ], + tab_offset + ) + self.show() self.last_displayed_body = None - if self.state.view_flow_mode == common.VIEW_FLOW_RESPONSE: - self.view_response() - else: - self.view_request() signals.flow_change.connect(self.sig_flow_change) + def tab_request(self): + if self.flow.intercepted and not self.flow.reply.acked and not self.flow.response: + return "Request intercepted" + else: + return "Request" + + def tab_response(self): + if self.flow.intercepted and not self.flow.reply.acked and self.flow.response: + return "Response intercepted" + else: + return "Response" + + def view_request(self): + return self.conn_text(self.flow.request) + + def view_response(self): + return self.conn_text(self.flow.response) + + + def sig_flow_change(self, sender, flow): if flow == self.flow: - if self.state.view_flow_mode == common.VIEW_FLOW_RESPONSE and self.flow.response: - self.view_response() - else: - self.view_request() + self.show() def content_view(self, viewmode, conn): if conn.content == CONTENT_MISSING: @@ -136,7 +159,7 @@ class FlowView(urwid.WidgetWrap): else: full = self.state.get_flow_setting( self.flow, - (self.state.view_flow_mode, "fullcontents"), + (self.tab_offset, "fullcontents"), False ) if full: @@ -157,7 +180,7 @@ class FlowView(urwid.WidgetWrap): def viewmode_get(self): override = self.state.get_flow_setting( self.flow, - (self.state.view_flow_mode, "prettyview") + (self.tab_offset, "prettyview") ) return self.state.default_body_view if override is None else override @@ -203,50 +226,6 @@ class FlowView(urwid.WidgetWrap): ] return searchable.Searchable(self.state, txt) - def _tab(self, content, attr): - p = urwid.Text(content) - p = urwid.Padding(p, align="left", width=("relative", 100)) - p = urwid.AttrWrap(p, attr) - return p - - def wrap_body(self, active, body): - parts = [] - - if self.flow.intercepted and not self.flow.reply.acked and not self.flow.response: - qt = "Request intercepted" - else: - qt = "Request" - if active == common.VIEW_FLOW_REQUEST: - parts.append(self._tab(qt, "heading")) - else: - parts.append(self._tab(qt, "heading_inactive")) - - if self.flow.intercepted and not self.flow.reply.acked and self.flow.response: - st = "Response intercepted" - else: - st = "Response" - if active == common.VIEW_FLOW_RESPONSE: - parts.append(self._tab(st, "heading")) - else: - parts.append(self._tab(st, "heading_inactive")) - - h = urwid.Columns(parts) - f = urwid.Frame( - body, - header=h - ) - return f - - def view_request(self): - self.state.view_flow_mode = common.VIEW_FLOW_REQUEST - body = self.conn_text(self.flow.request) - self._w = self.wrap_body(common.VIEW_FLOW_REQUEST, body) - - def view_response(self): - self.state.view_flow_mode = common.VIEW_FLOW_RESPONSE - body = self.conn_text(self.flow.response) - self._w = self.wrap_body(common.VIEW_FLOW_RESPONSE, body) - def set_method_raw(self, m): if m: self.flow.request.method = m @@ -320,7 +299,7 @@ class FlowView(urwid.WidgetWrap): self.edit_form(conn) def edit(self, part): - if self.state.view_flow_mode == common.VIEW_FLOW_REQUEST: + if self.tab_offset == TAB_REQ: message = self.flow.request else: if not self.flow.response: @@ -383,25 +362,25 @@ class FlowView(urwid.WidgetWrap): self.set_query, message ) ) - elif part == "u" and self.state.view_flow_mode == common.VIEW_FLOW_REQUEST: + elif part == "u" and self.tab_offset == TAB_REQ: signals.status_prompt.send( prompt = "URL", text = message.url, callback = self.set_url ) - elif part == "m" and self.state.view_flow_mode == common.VIEW_FLOW_REQUEST: + elif part == "m" and self.tab_offset == TAB_REQ: signals.status_prompt_onekey.send( prompt = "Method", keys = common.METHOD_OPTIONS, callback = self.edit_method ) - elif part == "c" and self.state.view_flow_mode == common.VIEW_FLOW_RESPONSE: + elif part == "c" and self.tab_offset == TAB_RESP: signals.status_prompt.send( prompt = "Code", text = str(message.code), callback = self.set_resp_code ) - elif part == "m" and self.state.view_flow_mode == common.VIEW_FLOW_RESPONSE: + elif part == "m" and self.tab_offset == TAB_RESP: signals.status_prompt.send( prompt = "Message", text = message.msg, @@ -422,7 +401,7 @@ class FlowView(urwid.WidgetWrap): signals.status_message.send(message="No more flows!") else: signals.pop_view_state.send(self) - self.master.view_flow(new_flow) + self.master.view_flow(new_flow, self.tab_offset) def view_next_flow(self, flow): return self._view_nextprev_flow("next", flow) @@ -433,7 +412,7 @@ class FlowView(urwid.WidgetWrap): def change_this_display_mode(self, t): self.state.add_flow_setting( self.flow, - (self.state.view_flow_mode, "prettyview"), + (self.tab_offset, "prettyview"), contentview.get_by_shortcut(t) ) signals.flow_change.send(self, flow = self.flow) @@ -443,7 +422,7 @@ class FlowView(urwid.WidgetWrap): val = CONTENT_MISSING else: val = None - if self.state.view_flow_mode == common.VIEW_FLOW_REQUEST: + if self.tab_offset == TAB_REQ: self.flow.request.content = val else: self.flow.response.content = val @@ -455,7 +434,7 @@ class FlowView(urwid.WidgetWrap): return key = common.shortcuts(key) - if self.state.view_flow_mode == common.VIEW_FLOW_REQUEST: + if self.tab_offset == TAB_REQ: conn = self.flow.request else: conn = self.flow.response @@ -463,11 +442,6 @@ class FlowView(urwid.WidgetWrap): if key == "q": signals.pop_view_state.send(self) return None - elif key == "tab": - if self.state.view_flow_mode == common.VIEW_FLOW_REQUEST: - self.view_response() - else: - self.view_request() elif key in ("up", "down", "page up", "page down"): # Why doesn't this just work?? self._w.keypress(size, key) @@ -478,7 +452,7 @@ class FlowView(urwid.WidgetWrap): self.master.accept_all() self.master.view_flow(self.flow) elif key == "b": - if self.state.view_flow_mode == common.VIEW_FLOW_REQUEST: + if self.tab_offset == TAB_REQ: common.ask_save_body("q", self.master, self.state, self.flow) else: common.ask_save_body("s", self.master, self.state, self.flow) @@ -497,7 +471,7 @@ class FlowView(urwid.WidgetWrap): self.master.view_flow(f) signals.status_message.send(message="Duplicated.") elif key == "e": - if self.state.view_flow_mode == common.VIEW_FLOW_REQUEST: + if self.tab_offset == TAB_REQ: signals.status_prompt_onekey.send( prompt = "Edit request", keys = ( @@ -527,13 +501,13 @@ class FlowView(urwid.WidgetWrap): signals.status_message.send(message="Loading all body data...") self.state.add_flow_setting( self.flow, - (self.state.view_flow_mode, "fullcontents"), + (self.tab_state, "fullcontents"), True ) signals.flow_change.send(self, flow = self.flow) signals.status_message.send(message="") elif key == "g": - if self.state.view_flow_mode == common.VIEW_FLOW_REQUEST: + if self.tab_offset == TAB_REQ: scope = "q" else: scope = "s" -- cgit v1.2.3 From 8f5cf833d08aba685263554d0bd89f922cd6afae Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Sun, 29 Mar 2015 19:21:54 +1300 Subject: Add flow detail view as a tab in the flow view --- libmproxy/console/flowview.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'libmproxy/console/flowview.py') diff --git a/libmproxy/console/flowview.py b/libmproxy/console/flowview.py index ffe499d7..514340c9 100644 --- a/libmproxy/console/flowview.py +++ b/libmproxy/console/flowview.py @@ -2,6 +2,7 @@ from __future__ import absolute_import import os, sys, copy import urwid from . import common, grideditor, contentview, signals, searchable, tabs +from . import flowdetailview from .. import utils, flow, controller from ..protocol.http import HTTPRequest, HTTPResponse, CONTENT_MISSING, decoded @@ -65,7 +66,6 @@ def _mkhelp(): ("w", "save all flows matching current limit"), ("W", "save this flow"), ("x", "delete body"), - ("X", "view flow details"), ("z", "encode/decode a request/response"), ("tab", "toggle request/response view"), ("space", "next flow"), @@ -121,6 +121,7 @@ class FlowView(tabs.Tabs): [ (self.tab_request, self.view_request), (self.tab_response, self.view_response), + (self.tab_details, self.view_details), ], tab_offset ) @@ -140,13 +141,17 @@ class FlowView(tabs.Tabs): else: return "Response" + def tab_details(self): + return "Detail" + def view_request(self): return self.conn_text(self.flow.request) def view_response(self): return self.conn_text(self.flow.response) - + def view_details(self): + return flowdetailview.flowdetails(self.state, self.flow) def sig_flow_change(self, sender, flow): if flow == self.flow: @@ -568,8 +573,6 @@ class FlowView(tabs.Tabs): callback = self.delete_body ) key = None - elif key == "X": - self.master.view_flowdetails(self.flow) elif key == "z": if conn: self.flow.backup() -- cgit v1.2.3 From e964983e8137ac7ae77a473dbb308ac910c72ca6 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Mon, 30 Mar 2015 11:53:10 +1300 Subject: Disable keystrokes requiring a request/response on details page --- libmproxy/console/flowview.py | 180 ++++++++++++++++++++++-------------------- 1 file changed, 95 insertions(+), 85 deletions(-) (limited to 'libmproxy/console/flowview.py') diff --git a/libmproxy/console/flowview.py b/libmproxy/console/flowview.py index 514340c9..538f42f0 100644 --- a/libmproxy/console/flowview.py +++ b/libmproxy/console/flowview.py @@ -67,10 +67,10 @@ def _mkhelp(): ("W", "save this flow"), ("x", "delete body"), ("z", "encode/decode a request/response"), - ("tab", "toggle request/response view"), + ("tab", "next tab"), ("space", "next flow"), ("|", "run script on this flow"), - ("/", "search in response body (case sensitive)"), + ("/", "search (case sensitive)"), ("n", "repeat search forward"), ("N", "repeat search backwards"), ] @@ -367,25 +367,25 @@ class FlowView(tabs.Tabs): self.set_query, message ) ) - elif part == "u" and self.tab_offset == TAB_REQ: + elif part == "u": signals.status_prompt.send( prompt = "URL", text = message.url, callback = self.set_url ) - elif part == "m" and self.tab_offset == TAB_REQ: + elif part == "m": signals.status_prompt_onekey.send( prompt = "Method", keys = common.METHOD_OPTIONS, callback = self.edit_method ) - elif part == "c" and self.tab_offset == TAB_RESP: + elif part == "c": signals.status_prompt.send( prompt = "Code", text = str(message.code), callback = self.set_resp_code ) - elif part == "m" and self.tab_offset == TAB_RESP: + elif part == "m": signals.status_prompt.send( prompt = "Message", text = message.msg, @@ -441,8 +441,10 @@ class FlowView(tabs.Tabs): key = common.shortcuts(key) if self.tab_offset == TAB_REQ: conn = self.flow.request - else: + elif self.tab_offset == TAB_RESP: conn = self.flow.response + else: + conn = None if key == "q": signals.pop_view_state.send(self) @@ -456,11 +458,6 @@ class FlowView(tabs.Tabs): elif key == "A": self.master.accept_all() self.master.view_flow(self.flow) - elif key == "b": - if self.tab_offset == TAB_REQ: - common.ask_save_body("q", self.master, self.state, self.flow) - else: - common.ask_save_body("s", self.master, self.state, self.flow) elif key == "d": if self.state.flow_count() == 1: self.master.view_flowlist() @@ -475,58 +472,6 @@ class FlowView(tabs.Tabs): f = self.master.duplicate_flow(self.flow) self.master.view_flow(f) signals.status_message.send(message="Duplicated.") - elif key == "e": - if self.tab_offset == TAB_REQ: - signals.status_prompt_onekey.send( - prompt = "Edit request", - keys = ( - ("query", "q"), - ("path", "p"), - ("url", "u"), - ("header", "h"), - ("form", "f"), - ("raw body", "r"), - ("method", "m"), - ), - callback = self.edit - ) - else: - signals.status_prompt_onekey.send( - prompt = "Edit response", - keys = ( - ("code", "c"), - ("message", "m"), - ("header", "h"), - ("raw body", "r"), - ), - callback = self.edit - ) - key = None - elif key == "f": - signals.status_message.send(message="Loading all body data...") - self.state.add_flow_setting( - self.flow, - (self.tab_state, "fullcontents"), - True - ) - signals.flow_change.send(self, flow = self.flow) - signals.status_message.send(message="") - elif key == "g": - if self.tab_offset == TAB_REQ: - 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")) - signals.status_prompt_onekey.send( - self, - prompt = "Display mode", - keys = p, - callback = self.change_this_display_mode - ) - key = None elif key == "p": self.view_prev_flow(self.flow) elif key == "r": @@ -547,34 +492,97 @@ class FlowView(tabs.Tabs): callback = self.master.save_one_flow, args = (self.flow,) ) - elif key == "v": - if conn and conn.content: - t = conn.headers["content-type"] or [None] - t = t[0] - if os.environ.has_key("EDITOR") or os.environ.has_key("PAGER"): - self.master.spawn_external_viewer(conn.content, t) - else: - signals.status_message.send( - message = "Error! Set $EDITOR or $PAGER." - ) elif key == "|": signals.status_prompt_path.send( prompt = "Send flow to script", callback = self.master.run_script_once, args = (self.flow,) ) - elif key == "x": - signals.status_prompt_onekey.send( - prompt = "Delete body", - keys = ( - ("completely", "c"), - ("mark as missing", "m"), - ), - callback = self.delete_body + + if not conn and key in "befgmxvz": + signals.status_message.send( + message = "Tab to the request or response", + expire = 1 ) - key = None - elif key == "z": - if conn: + elif conn: + if key == "b": + if self.tab_offset == TAB_REQ: + common.ask_save_body("q", self.master, self.state, self.flow) + else: + common.ask_save_body("s", self.master, self.state, self.flow) + elif key == "e": + if self.tab_offset == TAB_REQ: + signals.status_prompt_onekey.send( + prompt = "Edit request", + keys = ( + ("query", "q"), + ("path", "p"), + ("url", "u"), + ("header", "h"), + ("form", "f"), + ("raw body", "r"), + ("method", "m"), + ), + callback = self.edit + ) + else: + signals.status_prompt_onekey.send( + prompt = "Edit response", + keys = ( + ("code", "c"), + ("message", "m"), + ("header", "h"), + ("raw body", "r"), + ), + callback = self.edit + ) + key = None + elif key == "f": + signals.status_message.send(message="Loading all body data...") + self.state.add_flow_setting( + self.flow, + (self.tab_offset, "fullcontents"), + True + ) + signals.flow_change.send(self, flow = self.flow) + signals.status_message.send(message="") + elif key == "g": + if self.tab_offset == TAB_REQ: + 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")) + signals.status_prompt_onekey.send( + self, + prompt = "Display mode", + keys = p, + callback = self.change_this_display_mode + ) + key = None + elif key == "x": + signals.status_prompt_onekey.send( + prompt = "Delete body", + keys = ( + ("completely", "c"), + ("mark as missing", "m"), + ), + callback = self.delete_body + ) + key = None + elif key == "v": + if conn.content: + t = conn.headers["content-type"] or [None] + t = t[0] + if os.environ.has_key("EDITOR") or os.environ.has_key("PAGER"): + self.master.spawn_external_viewer(conn.content, t) + else: + signals.status_message.send( + message = "Error! Set $EDITOR or $PAGER." + ) + elif key == "z": self.flow.backup() e = conn.headers.get_first("content-encoding", "identity") if e != "identity": @@ -593,6 +601,8 @@ class FlowView(tabs.Tabs): args = (conn,) ) signals.flow_change.send(self, flow = self.flow) + else: + return super(self.__class__, self).keypress(size, key) else: return super(self.__class__, self).keypress(size, key) -- cgit v1.2.3 From 32ba6021b3c07efaa45a9223479151cd7e74ccbd Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Wed, 1 Apr 2015 09:25:50 +1300 Subject: console: improve handling of help contexts, fix key bindings in flow views --- libmproxy/console/flowview.py | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) (limited to 'libmproxy/console/flowview.py') diff --git a/libmproxy/console/flowview.py b/libmproxy/console/flowview.py index 538f42f0..6a3ced6e 100644 --- a/libmproxy/console/flowview.py +++ b/libmproxy/console/flowview.py @@ -434,6 +434,8 @@ class FlowView(tabs.Tabs): signals.flow_change.send(self, flow = self.flow) def keypress(self, size, key): + key = super(self.__class__, self).keypress(size, key) + if key == " ": self.view_next_flow(self.flow) return @@ -446,10 +448,7 @@ class FlowView(tabs.Tabs): else: conn = None - if key == "q": - signals.pop_view_state.send(self) - return None - elif key in ("up", "down", "page up", "page down"): + if key in ("up", "down", "page up", "page down"): # Why doesn't this just work?? self._w.keypress(size, key) elif key == "a": @@ -499,7 +498,7 @@ class FlowView(tabs.Tabs): args = (self.flow,) ) - if not conn and key in "befgmxvz": + if not conn and key in set(list("befgmxvz")): signals.status_message.send( message = "Tab to the request or response", expire = 1 @@ -601,10 +600,7 @@ class FlowView(tabs.Tabs): args = (conn,) ) signals.flow_change.send(self, flow = self.flow) - else: - return super(self.__class__, self).keypress(size, key) - else: - return super(self.__class__, self).keypress(size, key) + return key def encode_callback(self, key, conn): encoding_map = { -- cgit v1.2.3 From c794d362f93df3a13ed5ac96dd6a04f766f8fbbc Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Wed, 1 Apr 2015 10:34:58 +1300 Subject: Next/previous tab keybindings --- libmproxy/console/flowview.py | 1 + 1 file changed, 1 insertion(+) (limited to 'libmproxy/console/flowview.py') diff --git a/libmproxy/console/flowview.py b/libmproxy/console/flowview.py index 6a3ced6e..99844cb7 100644 --- a/libmproxy/console/flowview.py +++ b/libmproxy/console/flowview.py @@ -68,6 +68,7 @@ def _mkhelp(): ("x", "delete body"), ("z", "encode/decode a request/response"), ("tab", "next tab"), + ("h, l", "previous tab, next tab"), ("space", "next flow"), ("|", "run script on this flow"), ("/", "search (case sensitive)"), -- cgit v1.2.3 From e76467e977c061d92f88500b23f11bbf3cc365bb Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Tue, 7 Apr 2015 15:59:38 +1200 Subject: Refactor flow list state management - Use signal mechanism for state synchronisation - Move "Copy to clipboard" shortcut to "P" --- libmproxy/console/flowview.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'libmproxy/console/flowview.py') diff --git a/libmproxy/console/flowview.py b/libmproxy/console/flowview.py index 99844cb7..9776f2b1 100644 --- a/libmproxy/console/flowview.py +++ b/libmproxy/console/flowview.py @@ -20,7 +20,6 @@ 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") + @@ -60,6 +59,7 @@ def _mkhelp(): ), ("M", "change default body display mode"), ("p", "previous flow"), + ("P", "copy response(content/headers) to clipboard"), ("r", "replay request"), ("V", "revert changes to request"), ("v", "view body in external viewer"), @@ -546,7 +546,7 @@ class FlowView(tabs.Tabs): ) signals.flow_change.send(self, flow = self.flow) signals.status_message.send(message="") - elif key == "g": + elif key == "P": if self.tab_offset == TAB_REQ: scope = "q" else: -- cgit v1.2.3 From bea0bd236a60e3e6c80027448e51b7802394304a Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Tue, 14 Apr 2015 11:58:10 +1200 Subject: Housekeeping and cleanups - No output to stdout on load in examples - they muck up the test suite. - Use the odict module directly, rather than aliasing it. The small convenience this gives to scripters is not worth it. - Move the cookie tests from the flow test module to the protocol_http test module. --- libmproxy/console/flowview.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'libmproxy/console/flowview.py') diff --git a/libmproxy/console/flowview.py b/libmproxy/console/flowview.py index 9776f2b1..d7dc0d23 100644 --- a/libmproxy/console/flowview.py +++ b/libmproxy/console/flowview.py @@ -1,6 +1,7 @@ from __future__ import absolute_import import os, sys, copy import urwid +from netlib import odict from . import common, grideditor, contentview, signals, searchable, tabs from . import flowdetailview from .. import utils, flow, controller @@ -275,11 +276,11 @@ class FlowView(tabs.Tabs): signals.flow_change.send(self, flow = self.flow) def set_headers(self, lst, conn): - conn.headers = flow.ODictCaseless(lst) + conn.headers = odict.ODictCaseless(lst) signals.flow_change.send(self, flow = self.flow) def set_query(self, lst, conn): - conn.set_query(flow.ODict(lst)) + conn.set_query(odict.ODict(lst)) signals.flow_change.send(self, flow = self.flow) def set_path_components(self, lst, conn): @@ -287,7 +288,7 @@ class FlowView(tabs.Tabs): signals.flow_change.send(self, flow = self.flow) def set_form(self, lst, conn): - conn.set_form_urlencoded(flow.ODict(lst)) + conn.set_form_urlencoded(odict.ODict(lst)) signals.flow_change.send(self, flow = self.flow) def edit_form(self, conn): @@ -311,7 +312,7 @@ class FlowView(tabs.Tabs): if not self.flow.response: self.flow.response = HTTPResponse( self.flow.request.httpversion, - 200, "OK", flow.ODictCaseless(), "" + 200, "OK", odict.ODictCaseless(), "" ) self.flow.response.reply = controller.DummyReply() message = self.flow.response -- cgit v1.2.3 From f33b483110db7a62b45e77b693176e2fba0dede9 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Wed, 15 Apr 2015 09:43:15 +1200 Subject: Editor for request cookies --- libmproxy/console/flowview.py | 68 ++++++++++++++++++++++++++++++------------- 1 file changed, 47 insertions(+), 21 deletions(-) (limited to 'libmproxy/console/flowview.py') diff --git a/libmproxy/console/flowview.py b/libmproxy/console/flowview.py index d7dc0d23..3b1a92ec 100644 --- a/libmproxy/console/flowview.py +++ b/libmproxy/console/flowview.py @@ -1,14 +1,16 @@ from __future__ import absolute_import -import os, sys, copy +import os +import sys import urwid from netlib import odict from . import common, grideditor, contentview, signals, searchable, tabs from . import flowdetailview -from .. import utils, flow, controller +from .. import utils, controller from ..protocol.http import HTTPRequest, HTTPResponse, CONTENT_MISSING, decoded -class SearchError(Exception): pass +class SearchError(Exception): + pass def _mkhelp(): @@ -114,6 +116,7 @@ cache = utils.LRUCache(200) TAB_REQ = 0 TAB_RESP = 1 + class FlowView(tabs.Tabs): highlight_color = "focusfield" @@ -174,14 +177,14 @@ class FlowView(tabs.Tabs): else: limit = contentview.VIEW_CUTOFF description, text_objects = cache.get( - contentview.get_content_view, - viewmode, - tuple(tuple(i) for i in conn.headers.lst), - conn.content, - limit, - self.master.add_event, - isinstance(conn, HTTPRequest) - ) + contentview.get_content_view, + viewmode, + tuple(tuple(i) for i in conn.headers.lst), + conn.content, + limit, + self.master.add_event, + isinstance(conn, HTTPRequest) + ) return (description, text_objects) def viewmode_get(self): @@ -194,20 +197,23 @@ class FlowView(tabs.Tabs): def conn_text(self, conn): if conn: txt = common.format_keyvals( - [(h+":", v) for (h, v) in conn.headers.lst], - key = "header", - val = "text" - ) + [(h+":", v) for (h, v) in conn.headers.lst], + key = "header", + val = "text" + ) viewmode = self.viewmode_get() msg, body = self.content_view(viewmode, conn) - cols = [urwid.Text( + cols = [ + urwid.Text( [ ("heading", msg), ] ) ] - cols.append(urwid.Text([ + cols.append( + urwid.Text( + [ " ", ('heading', "["), ('heading_key', "m"), @@ -305,6 +311,11 @@ class FlowView(tabs.Tabs): if key == "y": self.edit_form(conn) + def set_cookies(self, lst, conn): + od = odict.ODict(lst) + conn.set_cookies(od) + signals.flow_change.send(self, flow = self.flow) + def edit(self, part): if self.tab_offset == TAB_REQ: message = self.flow.request @@ -318,6 +329,16 @@ class FlowView(tabs.Tabs): message = self.flow.response self.flow.backup() + if message == self.flow.request and part == "c": + self.master.view_grideditor( + grideditor.CookieEditor( + self.master, + message.get_cookies().lst, + self.set_cookies, + message + ) + ) + pass if part == "r": with decoded(message): # Fix an issue caused by some editors when editing a @@ -381,7 +402,7 @@ class FlowView(tabs.Tabs): keys = common.METHOD_OPTIONS, callback = self.edit_method ) - elif part == "c": + elif part == "o": signals.status_prompt.send( prompt = "Code", text = str(message.code), @@ -508,14 +529,19 @@ class FlowView(tabs.Tabs): elif conn: if key == "b": if self.tab_offset == TAB_REQ: - common.ask_save_body("q", self.master, self.state, self.flow) + common.ask_save_body( + "q", self.master, self.state, self.flow + ) else: - common.ask_save_body("s", self.master, self.state, self.flow) + common.ask_save_body( + "s", self.master, self.state, self.flow + ) elif key == "e": if self.tab_offset == TAB_REQ: signals.status_prompt_onekey.send( prompt = "Edit request", keys = ( + ("cookie", "c"), ("query", "q"), ("path", "p"), ("url", "u"), @@ -530,7 +556,7 @@ class FlowView(tabs.Tabs): signals.status_prompt_onekey.send( prompt = "Edit response", keys = ( - ("code", "c"), + ("code", "o"), ("message", "m"), ("header", "h"), ("raw body", "r"), -- cgit v1.2.3 From 52716e3439ceeb47d1fe8545a4875dc36866c37c Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Thu, 16 Apr 2015 10:57:12 +1200 Subject: console: first pass of a Set-cookie editor for responses --- libmproxy/console/flowview.py | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) (limited to 'libmproxy/console/flowview.py') diff --git a/libmproxy/console/flowview.py b/libmproxy/console/flowview.py index 3b1a92ec..497248de 100644 --- a/libmproxy/console/flowview.py +++ b/libmproxy/console/flowview.py @@ -316,6 +316,19 @@ class FlowView(tabs.Tabs): conn.set_cookies(od) signals.flow_change.send(self, flow = self.flow) + def set_setcookies(self, lst, conn): + vals = [] + for i in lst: + vals.append( + [ + i[0], + [i[1], odict.ODictCaseless(i[2])] + ] + ) + od = odict.ODict(vals) + conn.set_cookies(od) + signals.flow_change.send(self, flow = self.flow) + def edit(self, part): if self.tab_offset == TAB_REQ: message = self.flow.request @@ -338,7 +351,18 @@ class FlowView(tabs.Tabs): message ) ) - pass + if message == self.flow.response and part == "c": + flattened = [] + for k, v in message.get_cookies().items(): + flattened.append([k, v[0], v[1].lst]) + self.master.view_grideditor( + grideditor.SetCookieEditor( + self.master, + flattened, + self.set_setcookies, + message + ) + ) if part == "r": with decoded(message): # Fix an issue caused by some editors when editing a @@ -541,7 +565,7 @@ class FlowView(tabs.Tabs): signals.status_prompt_onekey.send( prompt = "Edit request", keys = ( - ("cookie", "c"), + ("cookies", "c"), ("query", "q"), ("path", "p"), ("url", "u"), @@ -556,6 +580,7 @@ class FlowView(tabs.Tabs): signals.status_prompt_onekey.send( prompt = "Edit response", keys = ( + ("cookies", "c"), ("code", "o"), ("message", "m"), ("header", "h"), -- cgit v1.2.3 From e963a9da4887268b03ceecf55086674121047056 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Fri, 17 Apr 2015 12:54:29 +1200 Subject: console: suport unary attributes Attributes with no value are treated as unary, e.g. "Secure" rather than "Secure=". If you really want to have an empty attribute value you can edit the header directly. Behind the scenes, restructure GridEditor to know about data conversion in and out of the editor. --- libmproxy/console/flowview.py | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) (limited to 'libmproxy/console/flowview.py') diff --git a/libmproxy/console/flowview.py b/libmproxy/console/flowview.py index 497248de..632b725e 100644 --- a/libmproxy/console/flowview.py +++ b/libmproxy/console/flowview.py @@ -290,7 +290,7 @@ class FlowView(tabs.Tabs): signals.flow_change.send(self, flow = self.flow) def set_path_components(self, lst, conn): - conn.set_path_components([i[0] for i in lst]) + conn.set_path_components(lst) signals.flow_change.send(self, flow = self.flow) def set_form(self, lst, conn): @@ -316,17 +316,8 @@ class FlowView(tabs.Tabs): conn.set_cookies(od) signals.flow_change.send(self, flow = self.flow) - def set_setcookies(self, lst, conn): - vals = [] - for i in lst: - vals.append( - [ - i[0], - [i[1], odict.ODictCaseless(i[2])] - ] - ) - od = odict.ODict(vals) - conn.set_cookies(od) + def set_setcookies(self, data, conn): + conn.set_cookies(data) signals.flow_change.send(self, flow = self.flow) def edit(self, part): @@ -352,13 +343,10 @@ class FlowView(tabs.Tabs): ) ) if message == self.flow.response and part == "c": - flattened = [] - for k, v in message.get_cookies().items(): - flattened.append([k, v[0], v[1].lst]) self.master.view_grideditor( grideditor.SetCookieEditor( self.master, - flattened, + message.get_cookies(), self.set_setcookies, message ) @@ -397,7 +385,6 @@ class FlowView(tabs.Tabs): ) elif part == "p": p = message.get_path_components() - p = [[i] for i in p] self.master.view_grideditor( grideditor.PathEditor( self.master, -- cgit v1.2.3 From a05a70d8168a07c92b2a3ecbbb1958d85532efe3 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Sat, 30 May 2015 12:03:28 +1200 Subject: Add coding style check, reformat. --- libmproxy/console/flowview.py | 101 +++++++++++++++++++++--------------------- 1 file changed, 51 insertions(+), 50 deletions(-) (limited to 'libmproxy/console/flowview.py') diff --git a/libmproxy/console/flowview.py b/libmproxy/console/flowview.py index 632b725e..43a40d69 100644 --- a/libmproxy/console/flowview.py +++ b/libmproxy/console/flowview.py @@ -24,42 +24,42 @@ def _mkhelp(): ("e", "edit request/response"), ("f", "load full body data"), ("m", "change body display mode for this entity"), - (None, - common.highlight_key("automatic", "a") + - [("text", ": automatic detection")] - ), - (None, - common.highlight_key("hex", "e") + - [("text", ": Hex")] - ), - (None, - common.highlight_key("html", "h") + - [("text", ": HTML")] - ), - (None, - common.highlight_key("image", "i") + - [("text", ": Image")] - ), - (None, - common.highlight_key("javascript", "j") + - [("text", ": JavaScript")] - ), - (None, - common.highlight_key("json", "s") + - [("text", ": JSON")] - ), - (None, - common.highlight_key("urlencoded", "u") + - [("text", ": URL-encoded data")] - ), - (None, - common.highlight_key("raw", "r") + - [("text", ": raw data")] - ), - (None, - common.highlight_key("xml", "x") + - [("text", ": XML")] - ), + (None, + common.highlight_key("automatic", "a") + + [("text", ": automatic detection")] + ), + (None, + common.highlight_key("hex", "e") + + [("text", ": Hex")] + ), + (None, + common.highlight_key("html", "h") + + [("text", ": HTML")] + ), + (None, + common.highlight_key("image", "i") + + [("text", ": Image")] + ), + (None, + common.highlight_key("javascript", "j") + + [("text", ": JavaScript")] + ), + (None, + common.highlight_key("json", "s") + + [("text", ": JSON")] + ), + (None, + common.highlight_key("urlencoded", "u") + + [("text", ": URL-encoded data")] + ), + (None, + common.highlight_key("raw", "r") + + [("text", ": raw data")] + ), + (None, + common.highlight_key("xml", "x") + + [("text", ": XML")] + ), ("M", "change default body display mode"), ("p", "previous flow"), ("P", "copy response(content/headers) to clipboard"), @@ -123,13 +123,13 @@ class FlowView(tabs.Tabs): def __init__(self, master, state, flow, tab_offset): self.master, self.state, self.flow = master, state, flow tabs.Tabs.__init__(self, - [ - (self.tab_request, self.view_request), - (self.tab_response, self.view_response), - (self.tab_details, self.view_details), - ], - tab_offset - ) + [ + (self.tab_request, self.view_request), + (self.tab_response, self.view_response), + (self.tab_details, self.view_details), + ], + tab_offset + ) self.show() self.last_displayed_body = None signals.flow_change.connect(self.sig_flow_change) @@ -173,7 +173,7 @@ class FlowView(tabs.Tabs): False ) if full: - limit = sys.maxint + limit = sys.maxsize else: limit = contentview.VIEW_CUTOFF description, text_objects = cache.get( @@ -197,7 +197,7 @@ class FlowView(tabs.Tabs): def conn_text(self, conn): if conn: txt = common.format_keyvals( - [(h+":", v) for (h, v) in conn.headers.lst], + [(h + ":", v) for (h, v) in conn.headers.lst], key = "header", val = "text" ) @@ -217,7 +217,7 @@ class FlowView(tabs.Tabs): " ", ('heading', "["), ('heading_key', "m"), - ('heading', (":%s]"%viewmode.name)), + ('heading', (":%s]" % viewmode.name)), ], align="right" ) @@ -272,8 +272,9 @@ class FlowView(tabs.Tabs): except ValueError: return None import BaseHTTPServer - if BaseHTTPServer.BaseHTTPRequestHandler.responses.has_key(int(code)): - response.msg = BaseHTTPServer.BaseHTTPRequestHandler.responses[int(code)][0] + if int(code) in BaseHTTPServer.BaseHTTPRequestHandler.responses: + response.msg = BaseHTTPServer.BaseHTTPRequestHandler.responses[ + int(code)][0] signals.flow_change.send(self, flow = self.flow) def set_resp_msg(self, msg): @@ -494,7 +495,7 @@ class FlowView(tabs.Tabs): elif key == "d": if self.state.flow_count() == 1: self.master.view_flowlist() - elif self.state.view.index(self.flow) == len(self.state.view)-1: + elif self.state.view.index(self.flow) == len(self.state.view) - 1: self.view_prev_flow(self.flow) else: self.view_next_flow(self.flow) @@ -615,7 +616,7 @@ class FlowView(tabs.Tabs): if conn.content: t = conn.headers["content-type"] or [None] t = t[0] - if os.environ.has_key("EDITOR") or os.environ.has_key("PAGER"): + if "EDITOR" in os.environ or "PAGER" in os.environ: self.master.spawn_external_viewer(conn.content, t) else: signals.status_message.send( -- cgit v1.2.3 From 57a61ae8fd420744d616765d13ad93dec3b3aa52 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Tue, 2 Jun 2015 12:09:07 +1200 Subject: console: convert add_event to a signal. --- libmproxy/console/flowview.py | 1 - 1 file changed, 1 deletion(-) (limited to 'libmproxy/console/flowview.py') diff --git a/libmproxy/console/flowview.py b/libmproxy/console/flowview.py index 43a40d69..c6c4c10d 100644 --- a/libmproxy/console/flowview.py +++ b/libmproxy/console/flowview.py @@ -182,7 +182,6 @@ class FlowView(tabs.Tabs): tuple(tuple(i) for i in conn.headers.lst), conn.content, limit, - self.master.add_event, isinstance(conn, HTTPRequest) ) return (description, text_objects) -- cgit v1.2.3