def run_script_once(self, command, f): sc = self.addons.get("scriptloader") try: with self.handlecontext(): sc.run_once(command, [f]) except mitmproxy.exceptions.AddonError as e: signals.add_log("Script error: %s" % e, "warn")
def run(self): self.ui = urwid.raw_display.Screen() self.ui.set_terminal_properties(256) self.set_palette(self.palette) self.loop = urwid.MainLoop( urwid.SolidFill("x"), screen = self.ui, handle_mouse = not self.options.no_mouse, ) self.ab = statusbar.ActionBar() if self.options.rfile: ret = self.load_flows_path(self.options.rfile) if ret and self.state.flow_count(): signals.add_log( "File truncated or corrupted. " "Loaded as many flows as possible.", "error" ) elif ret and not self.state.flow_count(): self.shutdown() print("Could not load file: {}".format(ret), file=sys.stderr) sys.exit(1) self.loop.set_alarm_in(0.01, self.ticker) if self.options.http2 and not tcp.HAS_ALPN: # pragma: no cover def http2err(*args, **kwargs): signals.status_message.send( message = "HTTP/2 disabled - OpenSSL 1.0.2+ required." " Use --no-http2 to silence this warning.", expire=5 ) self.loop.set_alarm_in(0.01, http2err) # It's not clear why we need to handle this explicitly - without this, # mitmproxy hangs on keyboard interrupt. Remove if we ever figure it # out. def exit(s, f): raise urwid.ExitMainLoop signal.signal(signal.SIGINT, exit) self.loop.set_alarm_in( 0.0001, lambda *args: self.view_flowlist() ) self.start() try: self.loop.run() except Exception: self.loop.stop() sys.stdout.flush() print(traceback.format_exc(), file=sys.stderr) print("mitmproxy has crashed!", file=sys.stderr) print("Please lodge a bug report at:", file=sys.stderr) print("\thttps://github.com/mitmproxy/mitmproxy", file=sys.stderr) print("Shutting down...", file=sys.stderr) sys.stderr.flush() self.shutdown()
def _run_script_method(self, method, s, f): status, val = s.run(method, f) if val: if status: signals.add_log("Method %s return: %s" % (method, val), "debug") else: signals.add_log( "Method %s error: %s" % (method, val[1]), "error")
def _run_script_method(self, method, s, f): status, val = s.run(method, f) if val: if status: signals.add_log("Method %s return: %s" % (method, val), "debug") else: signals.add_log("Method %s error: %s" % (method, val[1]), "error")
def _get_content_view(self, message, viewmode, max_lines, _): description, lines, error = contentviews.get_message_content_view( viewmode, message) if error: signals.add_log(error, "error") # Give hint that you have to tab for the response. if description == "No content" and isinstance(message, models.HTTPRequest): description = "No request content (press tab to view response)" # If the users has a wide terminal, he gets fewer lines; this should not be an issue. chars_per_line = 80 max_chars = max_lines * chars_per_line total_chars = 0 text_objects = [] for line in lines: txt = [] for (style, text) in line: if total_chars + len(text) > max_chars: text = text[:max_chars - total_chars] txt.append((style, text)) total_chars += len(text) if total_chars == max_chars: break # round up to the next line. total_chars = int( math.ceil(total_chars / chars_per_line) * chars_per_line) text_objects.append(urwid.Text(txt)) if total_chars == max_chars: text_objects.append( urwid.Text([ ("highlight", "Stopped displaying data after %d lines. Press " % max_lines), ("key", "f"), ("highlight", " to load all data.") ])) break return description, text_objects
def _get_content_view(self, message, viewmode, max_lines, _): description, lines, error = contentviews.get_message_content_view( viewmode, message ) if error: signals.add_log(error, "error") # Give hint that you have to tab for the response. if description == "No content" and isinstance(message, models.HTTPRequest): description = "No request content (press tab to view response)" # If the users has a wide terminal, he gets fewer lines; this should not be an issue. chars_per_line = 80 max_chars = max_lines * chars_per_line total_chars = 0 text_objects = [] for line in lines: txt = [] for (style, text) in line: if total_chars + len(text) > max_chars: text = text[:max_chars - total_chars] txt.append((style, text)) total_chars += len(text) if total_chars == max_chars: break # round up to the next line. total_chars = int(math.ceil(total_chars / chars_per_line) * chars_per_line) text_objects.append(urwid.Text(txt)) if total_chars == max_chars: text_objects.append(urwid.Text([ ("highlight", "Stopped displaying data after %d lines. Press " % max_lines), ("key", "f"), ("highlight", " to load all data.") ])) break return description, text_objects
def run_script_once(self, command, f): if not command: return signals.add_log("Running script on flow: %s" % command, "debug") try: s = script.Script(command) s.load() except script.ScriptException as e: signals.status_message.send( message='Error loading "{}".'.format(command) ) signals.add_log('Error loading "{}":\n{}'.format(command, e), "error") return if f.request: self._run_script_method("request", s, f) if f.response: self._run_script_method("response", s, f) if f.error: self._run_script_method("error", s, f) s.unload() signals.flow_change.send(self, flow = f)
def run_script_once(self, command, f): if not command: return signals.add_log("Running script on flow: %s" % command, "debug") try: s = script.Script(command) s.load() except script.ScriptException as e: signals.status_message.send( message='Error loading "{}".'.format(command)) signals.add_log('Error loading "{}":\n{}'.format(command, e), "error") return if f.request: self._run_script_method("request", s, f) if f.response: self._run_script_method("response", s, f) if f.error: self._run_script_method("error", s, f) s.unload() signals.flow_change.send(self, flow=f)
def keypress(self, xxx_todo_changeme, key): (maxcol,) = xxx_todo_changeme key = common.shortcuts(key) if key == "a": self.flow.accept_intercept(self.master) signals.flowlist_change.send(self) elif key == "d": if self.flow.killable: self.flow.kill(self.master) self.state.delete_flow(self.flow) signals.flowlist_change.send(self) elif key == "D": f = self.master.duplicate_flow(self.flow) self.master.state.set_focus_flow(f) signals.flowlist_change.send(self) elif key == "m": self.flow.marked = not self.flow.marked signals.flowlist_change.send(self) elif key == "M": if self.state.mark_filter: self.state.disable_marked_filter() else: self.state.enable_marked_filter() signals.flowlist_change.send(self) elif key == "r": try: self.master.replay_request(self.flow) except exceptions.ReplayException as e: signals.add_log("Replay error: %s" % e, "warn") signals.flowlist_change.send(self) elif key == "S": def stop_server_playback(response): if response == "y": self.master.options.server_replay = [] a = self.master.addons.get("serverplayback") if a.count(): signals.status_prompt_onekey.send( prompt = "Stop current server replay?", keys = ( ("yes", "y"), ("no", "n"), ), callback = stop_server_playback, ) else: signals.status_prompt_onekey.send( prompt = "Server Replay", keys = ( ("all flows", "a"), ("this flow", "t"), ), callback = self.server_replay_prompt, ) elif key == "U": for f in self.state.flows: f.marked = False signals.flowlist_change.send(self) elif key == "V": if not self.flow.modified(): signals.status_message.send(message="Flow not modified.") return self.state.revert(self.flow) signals.flowlist_change.send(self) signals.status_message.send(message="Reverted.") elif key == "w": signals.status_prompt_onekey.send( self, prompt = "Save", keys = ( ("listed flows", "l"), ("this flow", "t"), ), callback = self.save_flows_prompt, ) elif key == "X": if self.flow.killable: self.flow.kill(self.master) elif key == "enter": if self.flow.request: self.master.view_flow(self.flow) elif key == "|": signals.status_prompt_path.send( prompt = "Send flow to script", callback = self.master.run_script_once, args = (self.flow,) ) elif key == "E": signals.status_prompt_onekey.send( self, prompt = "Export to file", keys = [(e[0], e[1]) for e in export.EXPORTERS], callback = common.export_to_clip_or_file, args = (None, self.flow, common.ask_save_path) ) elif key == "C": signals.status_prompt_onekey.send( self, prompt = "Export to clipboard", keys = [(e[0], e[1]) for e in export.EXPORTERS], callback = common.export_to_clip_or_file, args = (None, self.flow, common.copy_to_clipboard_or_prompt) ) elif key == "b": common.ask_save_body(None, self.flow) else: return key
def add_log(self, e, level): signals.add_log(e, level)
def keypress(self, xxx_todo_changeme, key): (maxcol, ) = xxx_todo_changeme key = common.shortcuts(key) if key == "a": self.flow.accept_intercept(self.master) signals.flowlist_change.send(self) elif key == "d": if self.flow.killable: self.flow.kill(self.master) self.state.delete_flow(self.flow) signals.flowlist_change.send(self) elif key == "D": f = self.master.duplicate_flow(self.flow) self.master.state.set_focus_flow(f) signals.flowlist_change.send(self) elif key == "m": self.flow.marked = not self.flow.marked signals.flowlist_change.send(self) elif key == "M": if self.state.mark_filter: self.state.disable_marked_filter() else: self.state.enable_marked_filter() signals.flowlist_change.send(self) elif key == "r": try: self.master.replay_request(self.flow) except exceptions.ReplayException as e: signals.add_log("Replay error: %s" % e, "warn") signals.flowlist_change.send(self) elif key == "S": def stop_server_playback(response): if response == "y": self.master.options.server_replay = [] a = self.master.addons.get("serverplayback") if a.count(): signals.status_prompt_onekey.send( prompt="Stop current server replay?", keys=( ("yes", "y"), ("no", "n"), ), callback=stop_server_playback, ) else: signals.status_prompt_onekey.send( prompt="Server Replay", keys=( ("all flows", "a"), ("this flow", "t"), ), callback=self.server_replay_prompt, ) elif key == "U": for f in self.state.flows: f.marked = False signals.flowlist_change.send(self) elif key == "V": if not self.flow.modified(): signals.status_message.send(message="Flow not modified.") return self.state.revert(self.flow) signals.flowlist_change.send(self) signals.status_message.send(message="Reverted.") elif key == "w": signals.status_prompt_onekey.send( self, prompt="Save", keys=( ("listed flows", "l"), ("this flow", "t"), ), callback=self.save_flows_prompt, ) elif key == "X": if self.flow.killable: self.flow.kill(self.master) elif key == "enter": if self.flow.request: self.master.view_flow(self.flow) elif key == "|": signals.status_prompt_path.send( prompt="Send flow to script", callback=self.master.run_script_once, args=(self.flow, )) elif key == "E": signals.status_prompt_onekey.send( self, prompt="Export to file", keys=[(e[0], e[1]) for e in export.EXPORTERS], callback=common.export_to_clip_or_file, args=(None, self.flow, common.ask_save_path)) elif key == "C": signals.status_prompt_onekey.send( self, prompt="Export to clipboard", keys=[(e[0], e[1]) for e in export.EXPORTERS], callback=common.export_to_clip_or_file, args=(None, self.flow, common.copy_to_clipboard_or_prompt)) elif key == "b": common.ask_save_body(None, self.flow) else: return key
def keypress(self, size, key): conn = None # type: Optional[Union[models.HTTPRequest, models.HTTPResponse]] if self.tab_offset == TAB_REQ: conn = self.flow.request elif self.tab_offset == TAB_RESP: conn = self.flow.response key = super(self.__class__, self).keypress(size, key) # Special case: Space moves over to the next flow. # We need to catch that before applying common.shortcuts() if key == " ": self.view_next_flow(self.flow) return key = common.shortcuts(key) if key in ("up", "down", "page up", "page down"): # Pass scroll events to the wrapped widget self._w.keypress(size, key) elif key == "a": self.flow.accept_intercept(self.master) signals.flow_change.send(self, flow = self.flow) elif key == "A": self.master.accept_all() signals.flow_change.send(self, flow = self.flow) 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: self.view_prev_flow(self.flow) else: self.view_next_flow(self.flow) f = self.flow if f.killable: f.kill(self.master) self.state.delete_flow(f) elif key == "D": f = self.master.duplicate_flow(self.flow) signals.pop_view_state.send(self) self.master.view_flow(f) signals.status_message.send(message="Duplicated.") elif key == "p": self.view_prev_flow(self.flow) elif key == "r": try: self.master.replay_request(self.flow) except exceptions.ReplayException as e: signals.add_log("Replay error: %s" % e, "warn") signals.flow_change.send(self, flow = self.flow) elif key == "V": if self.flow.modified(): self.state.revert(self.flow) signals.flow_change.send(self, flow = self.flow) signals.status_message.send(message="Reverted.") else: signals.status_message.send(message="Flow not modified.") elif key == "W": signals.status_prompt_path.send( prompt = "Save this flow", callback = self.master.save_one_flow, args = (self.flow,) ) elif key == "|": signals.status_prompt_path.send( prompt = "Send flow to script", callback = self.master.run_script_once, args = (self.flow,) ) elif key == "e": self.flow = common.add_key_log(self.flow, key) if self.tab_offset == TAB_REQ: signals.status_prompt_onekey.send( prompt="Edit request", keys=( ("cookies", "c"), ("query", "q"), ("path", "p"), ("url", "u"), ("header", "h"), ("form", "f"), ("raw body", "r"), ("method", "m"), ), callback=self.edit ) elif self.tab_offset == TAB_RESP: signals.status_prompt_onekey.send( prompt="Edit response", keys=( ("cookies", "c"), ("code", "o"), ("message", "m"), ("header", "h"), ("raw body", "r"), ), callback=self.edit ) else: signals.status_message.send( message="Tab to the request or response", expire=1 ) elif key in set("bfgmxvzEC") and not conn: signals.status_message.send( message = "Tab to the request or response", expire = 1 ) return elif key == "b": if self.tab_offset == TAB_REQ: common.ask_save_body("q", self.flow) else: common.ask_save_body("s", self.flow) 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 == "m": p = list(contentviews.view_prompts) p.insert(0, ("Clear", "C")) signals.status_prompt_onekey.send( self, prompt = "Display mode", keys = p, callback = self.change_this_display_mode ) elif key == "E": if self.tab_offset == TAB_REQ: scope = "q" else: scope = "s" signals.status_prompt_onekey.send( self, prompt = "Export to file", keys = [(e[0], e[1]) for e in export.EXPORTERS], callback = common.export_to_clip_or_file, args = (scope, self.flow, common.ask_save_path) ) elif key == "C": if self.tab_offset == TAB_REQ: scope = "q" else: scope = "s" signals.status_prompt_onekey.send( self, prompt = "Export to clipboard", keys = [(e[0], e[1]) for e in export.EXPORTERS], callback = common.export_to_clip_or_file, args = (scope, self.flow, common.copy_to_clipboard_or_prompt) ) elif key == "x": conn.content = None signals.flow_change.send(self, flow=self.flow) elif key == "v": if conn.raw_content: t = conn.headers.get("content-type") if "EDITOR" in os.environ or "PAGER" in os.environ: self.master.spawn_external_viewer(conn.get_content(strict=False), t) else: signals.status_message.send( message = "Error! Set $EDITOR or $PAGER." ) elif key == "z": self.flow.backup() e = conn.headers.get("content-encoding", "identity") if e != "identity": try: conn.decode() except ValueError: signals.status_message.send( message = "Could not decode - invalid data?" ) else: signals.status_prompt_onekey.send( prompt = "Select encoding: ", keys = ( ("gzip", "z"), ("deflate", "d"), ("brotli", "b"), ), callback = self.encode_callback, args = (conn,) ) signals.flow_change.send(self, flow = self.flow) else: # Key is not handled here. return key
def _get_content_view(self, message, viewmode, max_lines, _): try: content = message.content if content != message.raw_content: enc = "[decoded {}]".format( message.headers.get("content-encoding")) else: enc = None except ValueError: content = message.raw_content enc = "[cannot decode]" try: query = None if isinstance(message, models.HTTPRequest): query = message.query description, lines = contentviews.get_content_view( viewmode, content, headers=message.headers, query=query) except exceptions.ContentViewException: s = "Content viewer failed: \n" + traceback.format_exc() signals.add_log(s, "error") description, lines = contentviews.get_content_view( contentviews.get("Raw"), content, headers=message.headers) description = description.replace( "Raw", "Couldn't parse: falling back to Raw") if enc: description = " ".join([enc, description]) # Give hint that you have to tab for the response. if description == "No content" and isinstance(message, models.HTTPRequest): description = "No request content (press tab to view response)" # If the users has a wide terminal, he gets fewer lines; this should not be an issue. chars_per_line = 80 max_chars = max_lines * chars_per_line total_chars = 0 text_objects = [] for line in lines: txt = [] for (style, text) in line: if total_chars + len(text) > max_chars: text = text[:max_chars - total_chars] txt.append((style, text)) total_chars += len(text) if total_chars == max_chars: break # round up to the next line. total_chars = int( math.ceil(total_chars / chars_per_line) * chars_per_line) text_objects.append(urwid.Text(txt)) if total_chars == max_chars: text_objects.append( urwid.Text([ ("highlight", "Stopped displaying data after %d lines. Press " % max_lines), ("key", "f"), ("highlight", " to load all data.") ])) break return description, text_objects
def _get_content_view(self, message, viewmode, max_lines, _): try: content = message.content if content != message.raw_content: enc = "[decoded {}]".format( message.headers.get("content-encoding") ) else: enc = None except ValueError: content = message.raw_content enc = "[cannot decode]" try: query = None if isinstance(message, models.HTTPRequest): query = message.query description, lines = contentviews.get_content_view( viewmode, content, headers=message.headers, query=query ) except exceptions.ContentViewException: s = "Content viewer failed: \n" + traceback.format_exc() signals.add_log(s, "error") description, lines = contentviews.get_content_view( contentviews.get("Raw"), content, headers=message.headers ) description = description.replace("Raw", "Couldn't parse: falling back to Raw") if enc: description = " ".join([enc, description]) # Give hint that you have to tab for the response. if description == "No content" and isinstance(message, models.HTTPRequest): description = "No request content (press tab to view response)" # If the users has a wide terminal, he gets fewer lines; this should not be an issue. chars_per_line = 80 max_chars = max_lines * chars_per_line total_chars = 0 text_objects = [] for line in lines: txt = [] for (style, text) in line: if total_chars + len(text) > max_chars: text = text[:max_chars - total_chars] txt.append((style, text)) total_chars += len(text) if total_chars == max_chars: break # round up to the next line. total_chars = int(math.ceil(total_chars / chars_per_line) * chars_per_line) text_objects.append(urwid.Text(txt)) if total_chars == max_chars: text_objects.append(urwid.Text([ ("highlight", "Stopped displaying data after %d lines. Press " % max_lines), ("key", "f"), ("highlight", " to load all data.") ])) break return description, text_objects
def keypress(self, xxx_todo_changeme, key): (maxcol,) = xxx_todo_changeme key = common.shortcuts(key) # Test keys are number 1 to 6, flow must me marked before run test on it. if key == "1": for f in self.state.flows: if f.marked: f.authentication = self.test_authentication(f) signals.flowlist_change.send(self) if key == "2": for f in self.state.flows: if f.marked: f.authentication = self.gather_authentication_result(f) signals.flowlist_change.send(self) if key == "3": cnt = 1 for f in self.state.flows: if f.marked: f.authorization = self.test_authorization(f) signals.flowlist_change.send(self) if key == "4": for f in self.state.flows: if f.marked: f.authorization = self.gather_authorization_result(f) signals.flowlist_change.send(self) # payu salt in req or resp if key == "5": for f in self.state.flows: if f.marked: f.payu_salt_leak = self.test_payu_salt_leak(f) signals.flowlist_change.send(self) # otp in resp if key == "6": for f in self.state.flows: if f.marked: f.otp_leak = self.test_otp_leak(f) signals.flowlist_change.send(self) if key == "R": self.master.repeater(self.flow) signals.status_message.send(message="Repeating request 64 times") signals.flowlist_change.send(self) if key == "a": self.flow.accept_intercept(self.master) signals.flowlist_change.send(self) elif key == "d": if self.flow.killable: self.flow.kill(self.master) self.state.delete_flow(self.flow) signals.flowlist_change.send(self) elif key == "D": f = self.master.duplicate_flow(self.flow) self.master.state.set_focus_flow(f) signals.flowlist_change.send(self) elif key == "f1": self.flow.authentication += 1 self.flow.authentication %= 3 signals.flowlist_change.send(self) elif key == "f2": self.flow.authorization += 1 self.flow.authorization %= 3 signals.flowlist_change.send(self) elif key == "f3": self.flow.payu_salt_leak += 1 self.flow.payu_salt_leak %= 3 signals.flowlist_change.send(self) elif key == "f4": self.flow.otp_leak += 1 self.flow.otp_leak %= 3 signals.flowlist_change.send(self) elif key == "u": for f in self.master.state.view: f.marked = not f.marked signals.flowlist_change.send(self) elif key == "m": self.flow.marked = not self.flow.marked signals.flowlist_change.send(self) elif key == "M": if self.state.mark_filter: self.state.disable_marked_filter() else: self.state.enable_marked_filter() signals.flowlist_change.send(self) elif key == "N": self.state.set_view_filter("!(.gif) & !(.js) & !(.css) & !(.ttf) & !(.png) & !(.svg) & !(gstatic) & !(.ico) & !(.jpg) & !(.jpeg) & !(.woff) & !(.woff2) & !(fbcdn) & !(google) & !(facebook)") signals.flowlist_change.send(self) elif key == "v": self.state.set_view_filter("") signals.flowlist_change.send(self) elif key == "r": try: self.master.replay_request(self.flow) except exceptions.ReplayException as e: signals.add_log("Replay error: %s" % e, "warn") signals.flowlist_change.send(self) elif key == "S": def stop_server_playback(response): if response == "y": self.master.options.server_replay = [] a = self.master.addons.get("serverplayback") if a.count(): signals.status_prompt_onekey.send( prompt = "Stop current server replay?", keys = ( ("yes", "y"), ("no", "n"), ), callback = stop_server_playback, ) else: signals.status_prompt_onekey.send( prompt = "Server Replay", keys = ( ("all flows", "a"), ("this flow", "t"), ), callback = self.server_replay_prompt, ) elif key == "U": for f in self.state.flows: f.marked = False signals.flowlist_change.send(self) elif key == "V": if not self.flow.modified(): signals.status_message.send(message="Flow not modified.") return self.state.revert(self.flow) signals.flowlist_change.send(self) signals.status_message.send(message="Reverted.") elif key == "w": signals.status_prompt_onekey.send( self, prompt = "Save", keys = (("listed flows as swagger", "s"), ("listed flows as report", "r"), ("listed flows as har", "h"), ("listed flows", "l"), ("this flow", "t"), ), callback = self.save_flows_prompt, ) elif key == "X": if self.flow.killable: self.flow.kill(self.master) elif key == "z": # create a copy since used in for loop copy_of_state_view = self.state.view[:] for f in copy_of_state_view: signals.add_log("Len of state.view %d " % len(self.state.view), level="info") if f.killable: f.kill(self.master) self.state.delete_flow(f) signals.flowlist_change.send(self) elif key == "enter": if self.flow.request: self.flow = common.add_key_log(self.flow, "enter") signals.flowlist_change.send(self) self.master.view_flow(self.flow) elif key == "|": signals.status_prompt_path.send( prompt = "Send flow to script", callback = self.master.run_script_once, args = (self.flow,) ) elif key == "E": signals.status_prompt_onekey.send( self, prompt = "Export to file", keys = [(e[0], e[1]) for e in export.EXPORTERS], callback = common.export_to_clip_or_file, args = (None, self.flow, common.ask_save_path) ) elif key == "C": signals.status_prompt_onekey.send( self, prompt = "Export to clipboard", keys = [(e[0], e[1]) for e in export.EXPORTERS], callback = common.export_to_clip_or_file, args = (None, self.flow, common.copy_to_clipboard_or_prompt) ) elif key == "b": common.ask_save_body(None, self.flow) else: return key
def keypress(self, size, key): conn = None # type: Optional[Union[models.HTTPRequest, models.HTTPResponse]] if self.tab_offset == TAB_REQ: conn = self.flow.request elif self.tab_offset == TAB_RESP: conn = self.flow.response key = super().keypress(size, key) # Special case: Space moves over to the next flow. # We need to catch that before applying common.shortcuts() if key == " ": self.view_next_flow(self.flow) return key = common.shortcuts(key) if key in ("up", "down", "page up", "page down"): # Pass scroll events to the wrapped widget self._w.keypress(size, key) elif key == "a": self.flow.resume(self.master) signals.flow_change.send(self, flow = self.flow) elif key == "A": self.master.accept_all() signals.flow_change.send(self, flow = self.flow) 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: self.view_prev_flow(self.flow) else: self.view_next_flow(self.flow) f = self.flow if f.killable: f.kill(self.master) self.state.delete_flow(f) elif key == "D": f = self.master.state.duplicate_flow(self.flow) signals.pop_view_state.send(self) self.master.view_flow(f) signals.status_message.send(message="Duplicated.") elif key == "p": self.view_prev_flow(self.flow) elif key == "r": try: self.master.replay_request(self.flow) except exceptions.ReplayException as e: signals.add_log("Replay error: %s" % e, "warn") signals.flow_change.send(self, flow = self.flow) elif key == "V": if self.flow.modified(): self.state.revert(self.flow) signals.flow_change.send(self, flow = self.flow) signals.status_message.send(message="Reverted.") else: signals.status_message.send(message="Flow not modified.") elif key == "W": signals.status_prompt_path.send( prompt = "Save this flow", callback = self.master.save_one_flow, args = (self.flow,) ) elif key == "|": signals.status_prompt_path.send( prompt = "Send flow to script", callback = self.master.run_script_once, args = (self.flow,) ) elif key == "e": if self.tab_offset == TAB_REQ: signals.status_prompt_onekey.send( prompt="Edit request", keys=( ("cookies", "c"), ("query", "q"), ("path", "p"), ("url", "u"), ("header", "h"), ("form", "f"), ("raw body", "r"), ("method", "m"), ), callback=self.edit ) elif self.tab_offset == TAB_RESP: signals.status_prompt_onekey.send( prompt="Edit response", keys=( ("cookies", "c"), ("code", "o"), ("message", "m"), ("header", "h"), ("raw body", "r"), ), callback=self.edit ) else: signals.status_message.send( message="Tab to the request or response", expire=1 ) elif key in set("bfgmxvzEC") and not conn: signals.status_message.send( message = "Tab to the request or response", expire = 1 ) return elif key == "b": if self.tab_offset == TAB_REQ: common.ask_save_body("q", self.flow) else: common.ask_save_body("s", self.flow) 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 == "m": p = list(contentviews.view_prompts) p.insert(0, ("Clear", "C")) signals.status_prompt_onekey.send( self, prompt = "Display mode", keys = p, callback = self.change_this_display_mode ) elif key == "E": if self.tab_offset == TAB_REQ: scope = "q" else: scope = "s" signals.status_prompt_onekey.send( self, prompt = "Export to file", keys = [(e[0], e[1]) for e in export.EXPORTERS], callback = common.export_to_clip_or_file, args = (scope, self.flow, common.ask_save_path) ) elif key == "C": if self.tab_offset == TAB_REQ: scope = "q" else: scope = "s" signals.status_prompt_onekey.send( self, prompt = "Export to clipboard", keys = [(e[0], e[1]) for e in export.EXPORTERS], callback = common.export_to_clip_or_file, args = (scope, self.flow, common.copy_to_clipboard_or_prompt) ) elif key == "x": conn.content = None signals.flow_change.send(self, flow=self.flow) elif key == "v": if conn.raw_content: t = conn.headers.get("content-type") if "EDITOR" in os.environ or "PAGER" in os.environ: self.master.spawn_external_viewer(conn.get_content(strict=False), t) else: signals.status_message.send( message = "Error! Set $EDITOR or $PAGER." ) elif key == "z": self.flow.backup() e = conn.headers.get("content-encoding", "identity") if e != "identity": try: conn.decode() except ValueError: signals.status_message.send( message = "Could not decode - invalid data?" ) else: signals.status_prompt_onekey.send( prompt = "Select encoding: ", keys = ( ("gzip", "z"), ("deflate", "d"), ("brotli", "b"), ), callback = self.encode_callback, args = (conn,) ) signals.flow_change.send(self, flow = self.flow) else: # Key is not handled here. return key