Repository: mitmproxy/mitmproxy

Issue:
mitmproxy crashes in following mode with filters that remove items from the display based on server response
##### Steps to reproduce the problem:
1. Set a display filter that specifies things that should not be displayed based on server response (eg "! ~bs foobar")
2. Switch to following mode
3. Send request
##### What is the expected behavior?

mitmproxy should either briefly show the request while waiting for the server response, or not show the request until it has the response.
##### What went wrong?

``` pytb
Traceback (most recent call last):
  File "/usr/local/Cellar/mitmproxy/0.16/libexec/lib/python2.7/site-packages/libmproxy/console/__init__.py", line 498, in run
    self.loop.run()
  File "/usr/local/Cellar/mitmproxy/0.16/libexec/vendor/lib/python2.7/site-packages/urwid/main_loop.py", line 278, in run
    self._run()
  File "/usr/local/Cellar/mitmproxy/0.16/libexec/vendor/lib/python2.7/site-packages/urwid/main_loop.py", line 376, in _run
    self.event_loop.run()
  File "/usr/local/Cellar/mitmproxy/0.16/libexec/vendor/lib/python2.7/site-packages/urwid/main_loop.py", line 682, in run
    self._loop()
  File "/usr/local/Cellar/mitmproxy/0.16/libexec/vendor/lib/python2.7/site-packages/urwid/main_loop.py", line 715, in _loop
    alarm_callback()
  File "/usr/local/Cellar/mitmproxy/0.16/libexec/vendor/lib/python2.7/site-packages/urwid/main_loop.py", line 164, in cb
    callback(self, user_data)
  File "/usr/local/Cellar/mitmproxy/0.16/libexec/lib/python2.7/site-packages/libmproxy/console/__init__.py", line 451, in ticker
    self.loop.draw_screen()
  File "/usr/local/Cellar/mitmproxy/0.16/libexec/vendor/lib/python2.7/site-packages/urwid/main_loop.py", line 578, in draw_screen
    canvas = self._topmost_widget.render(self.screen_size, focus=True)
  File "/usr/local/Cellar/mitmproxy/0.16/libexec/vendor/lib/python2.7/site-packages/urwid/widget.py", line 141, in cached_render
    canv = fn(self, size, focus=focus)
  File "/usr/local/Cellar/mitmproxy/0.16/libexec/vendor/lib/python2.7/site-packages/urwid/container.py", line 1083, in render
    focus and self.focus_part == 'body')
  File "/usr/local/Cellar/mitmproxy/0.16/libexec/vendor/lib/python2.7/site-packages/urwid/widget.py", line 141, in cached_render
    canv = fn(self, size, focus=focus)
  File "/usr/local/Cellar/mitmproxy/0.16/libexec/vendor/lib/python2.7/site-packages/urwid/decoration.py", line 225, in render
    canv = self._original_widget.render(size, focus=focus)
  File "/usr/local/Cellar/mitmproxy/0.16/libexec/vendor/lib/python2.7/site-packages/urwid/widget.py", line 141, in cached_render
    canv = fn(self, size, focus=focus)
  File "/usr/local/Cellar/mitmproxy/0.16/libexec/vendor/lib/python2.7/site-packages/urwid/listbox.py", line 457, in render
    (maxcol, maxrow), focus=focus)
  File "/usr/local/Cellar/mitmproxy/0.16/libexec/vendor/lib/python2.7/site-packages/urwid/listbox.py", line 342, in calculate_visible
    focus_widget, focus_pos = self.body.get_focus()
  File "/usr/local/Cellar/mitmproxy/0.16/libexec/lib/python2.7/site-packages/libmproxy/console/flowlist.py", line 288, in get_focus
    f, i = self.state.get_focus()
  File "/usr/local/Cellar/mitmproxy/0.16/libexec/lib/python2.7/site-packages/libmproxy/console/__init__.py", line 69, in get_focus
    return self.view[self.focus], self.focus
  File "/usr/local/Cellar/mitmproxy/0.16/libexec/lib/python2.7/site-packages/libmproxy/flow.py", line 383, in __getitem__
    return self._list[item]
IndexError: list index out of range
```
##### Any other comments?

This only applies when using ! on a filter that depends on server response (eg ~bs, or ( ~s & ~b )) without any other part of the filter depending on the existence of the server response (eg ! ~bs without an & ~s).

---

Mitmproxy Version: 0.16 (from Homebrew)
Operating System: OS X 10.9, Python 2.7.5



Discussion:

Resolving patch:
diff --git a/mitmproxy/console/__init__.py b/mitmproxy/console/__init__.py
--- a/mitmproxy/console/__init__.py
+++ b/mitmproxy/console/__init__.py
@@ -50,7 +50,7 @@ def add_flow(self, f):
         if self.focus is None:
             self.set_focus(0)
         elif self.follow_focus:
-            self.set_focus(len(self.view) - 1)
+            self.update_focus()
         self.set_flow_marked(f, False)
         return f
 
@@ -58,6 +58,8 @@ def update_flow(self, f):
         super(ConsoleState, self).update_flow(f)
         if self.focus is None:
             self.set_focus(0)
+        elif self.follow_focus:
+            self.update_focus()
         return f
 
     def set_limit(self, limit):
@@ -80,6 +82,9 @@ def set_focus(self, idx):
         else:
             self.focus = None
 
+    def update_focus(self):
+        self.set_focus(len(self.view) - 1)
+
     def set_focus_flow(self, f):
         self.set_focus(self.view.index(f))
 


Test patch: