diff --git a/libmproxy/console.py b/libmproxy/console.py index c48a41bc9..95faa0fd4 100644 --- a/libmproxy/console.py +++ b/libmproxy/console.py @@ -486,33 +486,7 @@ class ConnectionView(WWrap): if conn.content: t = conn.headers.get("content-type", [None]) t = t[0] - if t: - ext = mimetypes.guess_extension(t) or "" - else: - ext = "" - fd, name = tempfile.mkstemp(ext, "mproxy") - os.write(fd, conn.content) - os.close(fd) - t = conn.headers.get("content-type", [None]) - t = t[0] - - cmd = None - shell = False - - if t: - c = mailcap.getcaps() - cmd, _ = mailcap.findmatch(c, t, filename=name) - if cmd: - shell = True - if not cmd: - c = os.environ.get("PAGER") or os.environ.get("EDITOR") - cmd = [c, name] - ret = subprocess.call(cmd, shell=shell) - # Not sure why, unless we do this we get a visible cursor after - # spawning 'less'. - self.master.ui._curs_set(1) - self.master.ui.clear() - os.unlink(name) + self.master.spawn_external_viewer(conn.content, t) elif key == "w": if self.state.view_flow_mode == VIEW_FLOW_REQUEST: self.master.prompt("Save request body: ", self.save_body) @@ -521,16 +495,19 @@ class ConnectionView(WWrap): elif key == " ": self.master.view_next_flow(self.flow) elif key == "|": - self.master.path_prompt("Script:", self.run_script) + self.master.path_prompt("Script: ", self.run_script) return key def run_script(self, path): path = os.path.expanduser(path) try: - newflow = self.flow.run_script(path) + newflow, serr = self.flow.run_script(path) except flow.RunException, e: self.master.statusbar.message("Script error: %s"%e) return + if serr: + serr = "Script output:\n\n" + serr + self.master.spawn_external_viewer(serr, None) self.flow.load_state(newflow.get_state()) self.master.refresh_connection(self.flow) @@ -775,6 +752,33 @@ class ConsoleMaster(controller.Master): self.stickycookie = None self.stickyhosts = {} + def spawn_external_viewer(self, data, contenttype): + if contenttype: + ext = mimetypes.guess_extension(contenttype) or "" + else: + ext = "" + fd, name = tempfile.mkstemp(ext, "mproxy") + os.write(fd, data) + os.close(fd) + + cmd = None + shell = False + + if contenttype: + c = mailcap.getcaps() + cmd, _ = mailcap.findmatch(c, contenttype, filename=name) + if cmd: + shell = True + if not cmd: + c = os.environ.get("PAGER") or os.environ.get("EDITOR") + cmd = [c, name] + ret = subprocess.call(cmd, shell=shell) + # Not sure why, unless we do this we get a visible cursor after + # spawning 'less'. + self.ui._curs_set(1) + self.ui.clear() + os.unlink(name) + def set_palette(self): self.palette = [ ('body', 'black', 'dark cyan', 'standout'), diff --git a/libmproxy/flow.py b/libmproxy/flow.py index c0b96c90b..d3bba4b38 100644 --- a/libmproxy/flow.py +++ b/libmproxy/flow.py @@ -53,13 +53,19 @@ class Flow: def run_script(self, path): """ - Run a script on a flow, returning the modified flow. + Run a script on a flow. - Raises RunException if there's an error. + Returns a (flow, stderr output) tuple, or raises RunException if + there's an error. """ data = self.script_serialize() try: - p = subprocess.Popen([path], stdout=subprocess.PIPE, stdin=subprocess.PIPE) + p = subprocess.Popen( + [path], + stdout=subprocess.PIPE, + stdin=subprocess.PIPE, + stderr=subprocess.PIPE, + ) except OSError, e: raise RunException(e.args[1]) so, se = p.communicate(data) @@ -68,7 +74,7 @@ class Flow: f = Flow.script_deserialize(so) if not f: raise RunException("Invalid response from script.") - return f + return f, se def dump(self): data = dict( diff --git a/test/scripts/a b/test/scripts/a index 6973a44f7..fb4a7b82d 100755 --- a/test/scripts/a +++ b/test/scripts/a @@ -5,4 +5,5 @@ from libmproxy import script f = script.load_flow() f.request.host = "TESTOK" +print >> sys.stderr, "DEBUG" script.return_flow(f) diff --git a/test/test_flow.py b/test/test_flow.py index c97cc030f..3ff106d84 100644 --- a/test/test_flow.py +++ b/test/test_flow.py @@ -7,7 +7,8 @@ class uFlow(libpry.AutoTree): f = utils.tflow() f.response = utils.tresp() f.request = f.response.request - f = f.run_script("scripts/a") + f, se = f.run_script("scripts/a") + assert "DEBUG" == se.strip() assert f.request.host == "TESTOK" def test_run_script_err(self):