Repository: mitmproxy/mitmproxy

Issue:
Search inside a flow causes mitmproxy to crash
#### Problem Description

If you try to use the search feature inside a flow (by pressing '/') and type something to make a search, mitmproxy crashes.

#### Steps to reproduce the behavior:
1. Open mitmproxy and make a few requests
2. Selct one of the flows in the main screen and open it (by pressing Enter)
3. In the flow, press `/` and type something and then press Enter
4. Notice that mitmproxy crashes

#### System Information

$ mitmproxy --version
Mitmproxy: 5.0.0.dev (+413, commit 2f30981)
Python:    3.7.3
OpenSSL:   OpenSSL 1.1.0h  27 Mar 2018
Platform:  Linux-5.0.0-31-generic-x86_64-with-Ubuntu-19.04-disco



Discussion:
Can confirm, traceback:
```
Traceback (most recent call last):
  File "/Users/username/Projects/mitmproxy/mitmproxy/master.py", line 86, in run_loop
    loop()
  File "/Users/username/Envs/mitmproxy-0GFVzhJ3/lib/python3.7/site-packages/urwid/main_loop.py", line 286, in run
    self._run()
  File "/Users/username/Envs/mitmproxy-0GFVzhJ3/lib/python3.7/site-packages/urwid/main_loop.py", line 384, in _run
    self.event_loop.run()
  File "/Users/username/Envs/mitmproxy-0GFVzhJ3/lib/python3.7/site-packages/urwid/main_loop.py", line 1484, in run
    reraise(*exc_info)
  File "/Users/username/Envs/mitmproxy-0GFVzhJ3/lib/python3.7/site-packages/urwid/compat.py", line 58, in reraise
    raise value
  File "/usr/local/Cellar/python/3.7.4_1/Frameworks/Python.framework/Versions/3.7/lib/python3.7/asyncio/events.py", line 88, in _run
    self._context.run(self._callback, *self._args)
  File "/Users/username/Envs/mitmproxy-0GFVzhJ3/lib/python3.7/site-packages/urwid/raw_display.py", line 404, in <lambda>
    event_loop, callback, self.get_available_raw_input())
  File "/Users/username/Envs/mitmproxy-0GFVzhJ3/lib/python3.7/site-packages/urwid/raw_display.py", line 502, in parse_input
    callback(processed, processed_codes)
  File "/Users/username/Envs/mitmproxy-0GFVzhJ3/lib/python3.7/site-packages/urwid/main_loop.py", line 411, in _update
    self.process_input(keys)
  File "/Users/username/Envs/mitmproxy-0GFVzhJ3/lib/python3.7/site-packages/urwid/main_loop.py", line 511, in process_input
    k = self._topmost_widget.keypress(self.screen_size, k)
  File "/Users/username/Projects/mitmproxy/mitmproxy/tools/console/window.py", line 310, in keypress
    k = super().keypress(size, k)
  File "/Users/username/Envs/mitmproxy-0GFVzhJ3/lib/python3.7/site-packages/urwid/container.py", line 1119, in keypress
    return self.footer.keypress((maxcol,),key)
  File "/Users/username/Projects/mitmproxy/mitmproxy/tools/console/statusbar.py", line 198, in keypress
    return self.ab.keypress(*args, **kwargs)
  File "/Users/username/Projects/mitmproxy/mitmproxy/tools/console/statusbar.py", line 145, in keypress
    self.command_history.add_command(self._w.cbuf, True)
AttributeError: 'Edit' object has no attribute 'cbuf'
```

```
Mitmproxy: 5.0.0.dev (+444, commit bbb7eb6)
Python:    3.7.4
OpenSSL:   OpenSSL 1.1.0j  20 Nov 2018
Platform:  Darwin-18.7.0-x86_64-i386-64bit
```
@mhils Bug should be fixed in new pull request.

By the way, i'm wondering why console GUI used, instead of more advanced like QT, or GTK?
@peter-way I find it quite useful to be able to use mitmproxy GUI in machines I have SSH access on (keeping it running in a tmux session, for instance). Also, mitmweb interface should be the place to look for a greater "GUI-like" experience :) 

Resolving patch:
diff --git a/mitmproxy/tools/console/statusbar.py b/mitmproxy/tools/console/statusbar.py
--- a/mitmproxy/tools/console/statusbar.py
+++ b/mitmproxy/tools/console/statusbar.py
@@ -3,10 +3,10 @@
 
 import urwid
 
-import mitmproxy.tools.console.master # noqa
+import mitmproxy.tools.console.master  # noqa
+from mitmproxy.tools.console import commandexecutor
 from mitmproxy.tools.console import common
 from mitmproxy.tools.console import signals
-from mitmproxy.tools.console import commandexecutor
 from mitmproxy.tools.console.commander import commander
 
 
@@ -57,6 +57,7 @@ def sig_message(self, sender, message, expire=1):
             def cb(*args):
                 if w == self._w:
                     self.clear()
+
             signals.call_in.send(seconds=expire, callback=cb)
 
     def prep_prompt(self, p):
@@ -105,7 +106,13 @@ def sig_prompt_command(self, sender, partial: str = "", cursor: Optional[int] =
         )
         if cursor is not None:
             self._w.cbuf.cursor = cursor
-        self.prompting = commandexecutor.CommandExecutor(self.master)
+        self.prompting = self.execute_command
+
+    def execute_command(self, txt):
+        if txt.strip():
+            self.master.commands.call("commands.history.add", txt)
+        execute = commandexecutor.CommandExecutor(self.master)
+        execute(txt)
 
     def sig_prompt_onekey(self, sender, prompt, keys, callback, args=()):
         """
@@ -140,7 +147,6 @@ def keypress(self, size, k):
             elif k == "enter":
                 text = self._w.get_edit_text()
                 self.prompt_execute(text)
-                self.master.commands.call("commands.history.add", text)
             else:
                 if common.is_keypress(k):
                     self._w.keypress(size, k)
@@ -170,7 +176,7 @@ class StatusBar(urwid.WidgetWrap):
     keyctx = ""
 
     def __init__(
-        self, master: "mitmproxy.tools.console.master.ConsoleMaster"
+            self, master: "mitmproxy.tools.console.master.ConsoleMaster"
     ) -> None:
         self.master = master
         self.ib = urwid.WidgetWrap(urwid.Text(""))


Test patch: