Repository: mitmproxy/mitmproxy

Issue:
Console: Clearing content view crashes mitmproxy
##### Steps to reproduce the problem:

1. `mitmproxy`
2. `n g enter r enter tab m C`

```
Traceback (most recent call last):
  File "/media/sf_git/mitmproxy/mitmproxy/tools/console/master.py", line 290, in run
    self.loop.run()
  File "/home/user/venv/lib64/python3.5/site-packages/urwid/main_loop.py", line 278, in run
    self._run()
  File "/home/user/venv/lib64/python3.5/site-packages/urwid/main_loop.py", line 376, in _run
    self.event_loop.run()
  File "/home/user/venv/lib64/python3.5/site-packages/urwid/main_loop.py", line 682, in run
    self._loop()
  File "/home/user/venv/lib64/python3.5/site-packages/urwid/main_loop.py", line 719, in _loop
    self._watch_files[fd]()
  File "/home/user/venv/lib64/python3.5/site-packages/urwid/raw_display.py", line 393, in <lambda>
    event_loop, callback, self.get_available_raw_input())
  File "/home/user/venv/lib64/python3.5/site-packages/urwid/raw_display.py", line 493, in parse_input
    callback(processed, processed_codes)
  File "/home/user/venv/lib64/python3.5/site-packages/urwid/main_loop.py", line 403, in _update
    self.process_input(keys)
  File "/home/user/venv/lib64/python3.5/site-packages/urwid/main_loop.py", line 503, in process_input
    k = self._topmost_widget.keypress(self.screen_size, k)
  File "/media/sf_git/mitmproxy/mitmproxy/tools/console/window.py", line 84, in keypress
    k = super().keypress(size, k)
  File "/home/user/venv/lib64/python3.5/site-packages/urwid/container.py", line 1116, in keypress
    return self.footer.keypress((maxcol,),key)
  File "/media/sf_git/mitmproxy/mitmproxy/tools/console/statusbar.py", line 132, in keypress
    return self.master.ab.keypress(*args, **kwargs)
  File "/media/sf_git/mitmproxy/mitmproxy/tools/console/statusbar.py", line 85, in keypress
    self.prompt_execute(k)
  File "/media/sf_git/mitmproxy/mitmproxy/tools/console/statusbar.py", line 110, in prompt_execute
    msg = p(txt, *args)
  File "/media/sf_git/mitmproxy/mitmproxy/tools/console/flowview.py", line 486, in change_this_display_mode
    name = contentviews.get_by_shortcut(t).name
AttributeError: 'NoneType' object has no attribute 'name'
```

##### Any other comments? What have you tried so far?

`change_this_display_mode` has not logic to handle this case.


##### System information

Mitmproxy version: 0.19
Python version: 3.5.1
Platform: Linux-4.8.12-1-default-x86_64-with-glibc2.3.4
SSL version: OpenSSL 1.0.2j-fips  26 Sep 2016



Discussion:

Resolving patch:
diff --git a/mitmproxy/tools/console/flowview.py b/mitmproxy/tools/console/flowview.py
--- a/mitmproxy/tools/console/flowview.py
+++ b/mitmproxy/tools/console/flowview.py
@@ -1,23 +1,23 @@
 import math
 import os
 import sys
+from functools import lru_cache
+from typing import Optional, Union  # noqa
 
 import urwid
-from mitmproxy import exceptions
-from typing import Optional, Union  # noqa
 
 from mitmproxy import contentviews
+from mitmproxy import exceptions
+from mitmproxy import export
 from mitmproxy import http
+from mitmproxy.net.http import Headers
+from mitmproxy.net.http import status_codes
 from mitmproxy.tools.console import common
 from mitmproxy.tools.console import flowdetailview
 from mitmproxy.tools.console import grideditor
 from mitmproxy.tools.console import searchable
 from mitmproxy.tools.console import signals
 from mitmproxy.tools.console import tabs
-from mitmproxy import export
-from mitmproxy.net.http import Headers
-from mitmproxy.net.http import status_codes
-from functools import lru_cache
 
 
 class SearchError(Exception):
@@ -483,9 +483,12 @@ def view_prev_flow(self, flow):
         return self._view_nextprev_flow(self.view.index(flow) - 1, flow)
 
     def change_this_display_mode(self, t):
-        name = contentviews.get_by_shortcut(t).name
-        self.view.settings[self.flow][(self.tab_offset, "prettyview")] = name
-        signals.flow_change.send(self, flow = self.flow)
+        view = contentviews.get_by_shortcut(t)
+        if view:
+            self.view.settings[self.flow][(self.tab_offset, "prettyview")] = view.name
+        else:
+            self.view.settings[self.flow][(self.tab_offset, "prettyview")] = None
+        signals.flow_change.send(self, flow=self.flow)
 
     def keypress(self, size, key):
         conn = None  # type: Optional[Union[http.HTTPRequest, http.HTTPResponse]]


Test patch: