# Buggy code
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":
        self.master.replay_request(self.flow)
        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


# Traceback (AttributeError)
user@user-ubuntu:~$ mitmproxy
Exception ignored in: <bound method Reply.__del__ of <mitmproxy.controller.Reply object at 0x7f69de8646a0>>
Traceback (most recent call last):
File "/media/sf_git/mitmproxy/mitmproxy/controller.py", line 269, in __del__
raise exceptions.ControlException("Un-acked message: %s" % self.obj)
mitmproxy.exceptions.ControlException: Un-acked message: <HTTPFlow
request = Request(GET www.example.com:80/)
server_conn = <ServerConnection: www.example.com:80>>
Exception ignored in: <bound method Reply.__del__ of <mitmproxy.controller.Reply object at 0x7f69de864da0>>
Traceback (most recent call last):
File "/media/sf_git/mitmproxy/mitmproxy/controller.py", line 269, in __del__
raise exceptions.ControlException("Un-acked message: %s" % self.obj)
mitmproxy.exceptions.ControlException: Un-acked message: <HTTPFlow
request = Request(GET www.example.com:80/)
response = Response(200 OK, text/html, 1.24k)
server_conn = <ServerConnection: www.example.com:80>>
rTraceback (most recent call last):
File "/media/sf_git/mitmproxy/mitmproxy/console/master.py", line 502, in run
self.loop.run()
File "/usr/local/lib/python3.5/dist-packages/urwid/main_loop.py", line 278, in run
self._run()
File "/usr/local/lib/python3.5/dist-packages/urwid/main_loop.py", line 376, in _run
self.event_loop.run()
File "/usr/local/lib/python3.5/dist-packages/urwid/main_loop.py", line 682, in run
self._loop()
File "/usr/local/lib/python3.5/dist-packages/urwid/main_loop.py", line 715, in _loop
alarm_callback()
File "/usr/local/lib/python3.5/dist-packages/urwid/main_loop.py", line 164, in cb
callback(self, user_data)
File "/media/sf_git/mitmproxy/mitmproxy/console/master.py", line 448, in ticker
changed = self.tick(timeout=0)
File "/media/sf_git/mitmproxy/mitmproxy/flow/master.py", line 140, in tick
return super(FlowMaster, self).tick(timeout)
File "/media/sf_git/mitmproxy/mitmproxy/controller.py", line 136, in tick
handle_func(obj)
File "/media/sf_git/mitmproxy/mitmproxy/controller.py", line 219, in wrapper
master.addons(f.__name__, message)
File "/media/sf_git/mitmproxy/mitmproxy/addons.py", line 64, in __call__
self.invoke(i, name, *args, **kwargs)
File "/media/sf_git/mitmproxy/mitmproxy/addons.py", line 60, in invoke
func(*args, **kwargs)
File "/media/sf_git/mitmproxy/mitmproxy/builtins/setheaders.py", line 39, in response
self.run(flow, flow.response.headers)
AttributeError: 'NoneType' object has no attribute 'headers'

mitmproxy has crashed!
Please lodge a bug report at:
https://github.com/mitmproxy/mitmproxy
Shutting down...
rrrrrrrrrrException ignored in: <bound method Reply.__del__ of <mitmproxy.controller.Reply object at 0x7f69df0c2c18>>
Traceback (most recent call last):
File "/media/sf_git/mitmproxy/mitmproxy/controller.py", line 269, in __del__
mitmproxy.exceptions.ControlException: Un-acked message: <HTTPFlow
request = Request(GET www.example.com:80/)
response = Response(200 OK, text/html, 1.24k)
error = Connection killed
server_conn = <ServerConnection: www.example.com:80>>
user@user-ubuntu:~$ mitmproxy
rException ignored in: <bound method Reply.__del__ of <mitmproxy.controller.Reply object at 0x7f17c5270ac8>>
Traceback (most recent call last):
File "/media/sf_git/mitmproxy/mitmproxy/controller.py", line 269, in __del__
raise exceptions.ControlException("Un-acked message: %s" % self.obj)
mitmproxy.exceptions.ControlException: Un-acked message: <HTTPFlow
request = Request(GET www.example.com:80/)
response = Response(200 OK, text/html, 1.24k)
server_conn = <ServerConnection: www.example.com:80>>
rException ignored in: <bound method Reply.__del__ of <mitmproxy.controller.Reply object at 0x7f17c5291908>>
Traceback (most recent call last):
File "/media/sf_git/mitmproxy/mitmproxy/controller.py", line 269, in __del__
raise exceptions.ControlException("Un-acked message: %s" % self.obj)
mitmproxy.exceptions.ControlException: Un-acked message: <HTTPFlow
request = Request(GET www.example.com:80/)
response = Response(200 OK, text/html, 1.24k)
server_conn = <ServerConnection: www.example.com:80>>
Traceback (most recent call last):
File "/media/sf_git/mitmproxy/mitmproxy/console/master.py", line 502, in run
self.loop.run()
File "/usr/local/lib/python3.5/dist-packages/urwid/main_loop.py", line 278, in run
self._run()
File "/usr/local/lib/python3.5/dist-packages/urwid/main_loop.py", line 376, in _run
self.event_loop.run()
File "/usr/local/lib/python3.5/dist-packages/urwid/main_loop.py", line 682, in run
self._loop()
File "/usr/local/lib/python3.5/dist-packages/urwid/main_loop.py", line 715, in _loop
alarm_callback()
File "/usr/local/lib/python3.5/dist-packages/urwid/main_loop.py", line 164, in cb
callback(self, user_data)
File "/media/sf_git/mitmproxy/mitmproxy/console/master.py", line 448, in ticker
changed = self.tick(timeout=0)
File "/media/sf_git/mitmproxy/mitmproxy/flow/master.py", line 140, in tick
return super(FlowMaster, self).tick(timeout)
File "/media/sf_git/mitmproxy/mitmproxy/controller.py", line 136, in tick
handle_func(obj)
File "/media/sf_git/mitmproxy/mitmproxy/controller.py", line 219, in wrapper
master.addons(f.__name__, message)
File "/media/sf_git/mitmproxy/mitmproxy/addons.py", line 64, in __call__
self.invoke(i, name, *args, **kwargs)
File "/media/sf_git/mitmproxy/mitmproxy/addons.py", line 60, in invoke
func(*args, **kwargs)
File "/media/sf_git/mitmproxy/mitmproxy/builtins/setheaders.py", line 39, in response
self.run(flow, flow.response.headers)
AttributeError: 'NoneType' object has no attribute 'headers'

mitmproxy has crashed!
Please lodge a bug report at:
https://github.com/mitmproxy/mitmproxy
Shutting down...

# Fixed code
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":
        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