prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  mitmdump does not apply filter to saved data
  ##### Steps to reproduce the problem:
  
  1. I captured some traffic, and ran the following to filter it:
  
  ```
  $ mitmdump -r traffic.mitm -w out.mitm '~u main.css'
  Proxy server listening at http://[::]:8080
  172.16.122.1:51049: GET https://www.sjoerdlangkemper.nl/css/main.css
                   << 304 Not Modified 0b
  $
  ```
  
  It displays only the matched URL, but it saves all traffic. When done, out.mitm contains the same requests and responses as traffic.mitm. I.e. `mitmproxy -r out.mitm` shows a lot of requests, where I would expect only the request for main.css.
  
  
  ##### Any other comments? What have you tried so far?
  
  I tried this with release 2.0.2, and there it worked as expected. This issue seems to be similar to #1089.
  
  ##### System information
  
  ```
  $ mitmdump --version
  Mitmproxy version: 3.0.0 (2.0.0dev0965-0x168c72a) 
  Python version: 3.5.2
  Platform: Linux-4.4.0-98-generic-x86_64-with-Ubuntu-16.04-xenial
  SSL version: OpenSSL 1.1.0f  25 May 2017
  Linux distro: Ubuntu 16.04 xenial
  ```
  
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `mitmproxy/addons/save.py`
  Content:
  ```
  1 import os.path
  2 import typing
  3 
  4 from mitmproxy import exceptions
  5 from mitmproxy import flowfilter
  6 from mitmproxy import io
  7 from mitmproxy import ctx
  8 from mitmproxy import flow
  9 
  10 
  11 class Save:
  12     def __init__(self):
  13         self.stream = None
  14         self.filt = None
  15         self.active_flows = set()  # type: Set[flow.Flow]
  16 
  17     def open_file(self, path):
  18         if path.startswith("+"):
  19             path = path[1:]
  20             mode = "ab"
  21         else:
  22             mode = "wb"
  23         path = os.path.expanduser(path)
  24         return open(path, mode)
  25 
  26     def start_stream_to_path(self, path, flt):
  27         try:
  28             f = self.open_file(path)
  29         except IOError as v:
  30             raise exceptions.OptionsError(str(v))
  31         self.stream = io.FilteredFlowWriter(f, flt)
  32         self.active_flows = set()
  33 
  34     def configure(self, updated):
  35         # We're already streaming - stop the previous stream and restart
  36         if "save_stream_filter" in updated:
  37             if ctx.options.save_stream_filter:
  38                 self.filt = flowfilter.parse(ctx.options.save_stream_filter)
  39                 if not self.filt:
  40                     raise exceptions.OptionsError(
  41                         "Invalid filter specification: %s" % ctx.options.save_stream_filter
  42                     )
  43             else:
  44                 self.filt = None
  45         if "save_stream_file" in updated:
  46             if self.stream:
  47                 self.done()
  48             if ctx.options.save_stream_file:
  49                 self.start_stream_to_path(ctx.options.save_stream_file, self.filt)
  50 
  51     def save(self, flows: typing.Sequence[flow.Flow], path: str) -> None:
  52         """
  53             Save flows to a file. If the path starts with a +, flows are
  54             appended to the file, otherwise it is over-written.
  55         """
  56         try:
  57             f = self.open_file(path)
  58         except IOError as v:
  59             raise exceptions.CommandError(v) from v
  60         stream = io.FlowWriter(f)
  61         for i in flows:
  62             stream.add(i)
  63         f.close()
  64         ctx.log.alert("Saved %s flows." % len(flows))
  65 
  66     def load(self, l):
  67         l.add_command("save.file", self.save)
  68 
  69     def tcp_start(self, flow):
  70         if self.stream:
  71             self.active_flows.add(flow)
  72 
  73     def tcp_end(self, flow):
  74         if self.stream:
  75             self.stream.add(flow)
  76             self.active_flows.discard(flow)
  77 
  78     def response(self, flow):
  79         if self.stream:
  80             self.stream.add(flow)
  81             self.active_flows.discard(flow)
  82 
  83     def request(self, flow):
  84         if self.stream:
  85             self.active_flows.add(flow)
  86 
  87     def done(self):
  88         if self.stream:
  89             for f in self.active_flows:
  90                 self.stream.add(f)
  91             self.active_flows = set([])
  92             self.stream.fo.close()
  93             self.stream = None
  94
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/mitmproxy/addons/save.py b/mitmproxy/addons/save.py
  --- a/mitmproxy/addons/save.py
  +++ b/mitmproxy/addons/save.py
  @@ -42,7 +42,7 @@
                       )
               else:
                   self.filt = None
  -        if "save_stream_file" in updated:
  +        if "save_stream_file" in updated or "save_stream_filter" in updated:
               if self.stream:
                   self.done()
               if ctx.options.save_stream_file:
  
verification_info: {"golden_diff": "diff --git a/mitmproxy/addons/save.py b/mitmproxy/addons/save.py\n--- a/mitmproxy/addons/save.py\n+++ b/mitmproxy/addons/save.py\n@@ -42,7 +42,7 @@\n                     )\n             else:\n                 self.filt = None\n-        if \"save_stream_file\" in updated:\n+        if \"save_stream_file\" in updated or \"save_stream_filter\" in updated:\n             if self.stream:\n                 self.done()\n             if ctx.options.save_stream_file:\n", "issue": "mitmdump does not apply filter to saved data\n##### Steps to reproduce the problem:\r\n\r\n1. I captured some traffic, and ran the following to filter it:\r\n\r\n```\r\n$ mitmdump -r traffic.mitm -w out.mitm '~u main.css'\r\nProxy server listening at http://[::]:8080\r\n172.16.122.1:51049: GET https://www.sjoerdlangkemper.nl/css/main.css\r\n                 << 304 Not Modified 0b\r\n$\r\n```\r\n\r\nIt displays only the matched URL, but it saves all traffic. When done, out.mitm contains the same requests and responses as traffic.mitm. I.e. `mitmproxy -r out.mitm` shows a lot of requests, where I would expect only the request for main.css.\r\n\r\n\r\n##### Any other comments? What have you tried so far?\r\n\r\nI tried this with release 2.0.2, and there it worked as expected. This issue seems to be similar to #1089.\r\n\r\n##### System information\r\n\r\n```\r\n$ mitmdump --version\r\nMitmproxy version: 3.0.0 (2.0.0dev0965-0x168c72a) \r\nPython version: 3.5.2\r\nPlatform: Linux-4.4.0-98-generic-x86_64-with-Ubuntu-16.04-xenial\r\nSSL version: OpenSSL 1.1.0f  25 May 2017\r\nLinux distro: Ubuntu 16.04 xenial\r\n```\r\n\n", "before_files": [{"content": "import os.path\nimport typing\n\nfrom mitmproxy import exceptions\nfrom mitmproxy import flowfilter\nfrom mitmproxy import io\nfrom mitmproxy import ctx\nfrom mitmproxy import flow\n\n\nclass Save:\n    def __init__(self):\n        self.stream = None\n        self.filt = None\n        self.active_flows = set()  # type: Set[flow.Flow]\n\n    def open_file(self, path):\n        if path.startswith(\"+\"):\n            path = path[1:]\n            mode = \"ab\"\n        else:\n            mode = \"wb\"\n        path = os.path.expanduser(path)\n        return open(path, mode)\n\n    def start_stream_to_path(self, path, flt):\n        try:\n            f = self.open_file(path)\n        except IOError as v:\n            raise exceptions.OptionsError(str(v))\n        self.stream = io.FilteredFlowWriter(f, flt)\n        self.active_flows = set()\n\n    def configure(self, updated):\n        # We're already streaming - stop the previous stream and restart\n        if \"save_stream_filter\" in updated:\n            if ctx.options.save_stream_filter:\n                self.filt = flowfilter.parse(ctx.options.save_stream_filter)\n                if not self.filt:\n                    raise exceptions.OptionsError(\n                        \"Invalid filter specification: %s\" % ctx.options.save_stream_filter\n                    )\n            else:\n                self.filt = None\n        if \"save_stream_file\" in updated:\n            if self.stream:\n                self.done()\n            if ctx.options.save_stream_file:\n                self.start_stream_to_path(ctx.options.save_stream_file, self.filt)\n\n    def save(self, flows: typing.Sequence[flow.Flow], path: str) -> None:\n        \"\"\"\n            Save flows to a file. If the path starts with a +, flows are\n            appended to the file, otherwise it is over-written.\n        \"\"\"\n        try:\n            f = self.open_file(path)\n        except IOError as v:\n            raise exceptions.CommandError(v) from v\n        stream = io.FlowWriter(f)\n        for i in flows:\n            stream.add(i)\n        f.close()\n        ctx.log.alert(\"Saved %s flows.\" % len(flows))\n\n    def load(self, l):\n        l.add_command(\"save.file\", self.save)\n\n    def tcp_start(self, flow):\n        if self.stream:\n            self.active_flows.add(flow)\n\n    def tcp_end(self, flow):\n        if self.stream:\n            self.stream.add(flow)\n            self.active_flows.discard(flow)\n\n    def response(self, flow):\n        if self.stream:\n            self.stream.add(flow)\n            self.active_flows.discard(flow)\n\n    def request(self, flow):\n        if self.stream:\n            self.active_flows.add(flow)\n\n    def done(self):\n        if self.stream:\n            for f in self.active_flows:\n                self.stream.add(f)\n            self.active_flows = set([])\n            self.stream.fo.close()\n            self.stream = None\n", "path": "mitmproxy/addons/save.py"}], "after_files": [{"content": "import os.path\nimport typing\n\nfrom mitmproxy import exceptions\nfrom mitmproxy import flowfilter\nfrom mitmproxy import io\nfrom mitmproxy import ctx\nfrom mitmproxy import flow\n\n\nclass Save:\n    def __init__(self):\n        self.stream = None\n        self.filt = None\n        self.active_flows = set()  # type: Set[flow.Flow]\n\n    def open_file(self, path):\n        if path.startswith(\"+\"):\n            path = path[1:]\n            mode = \"ab\"\n        else:\n            mode = \"wb\"\n        path = os.path.expanduser(path)\n        return open(path, mode)\n\n    def start_stream_to_path(self, path, flt):\n        try:\n            f = self.open_file(path)\n        except IOError as v:\n            raise exceptions.OptionsError(str(v))\n        self.stream = io.FilteredFlowWriter(f, flt)\n        self.active_flows = set()\n\n    def configure(self, updated):\n        # We're already streaming - stop the previous stream and restart\n        if \"save_stream_filter\" in updated:\n            if ctx.options.save_stream_filter:\n                self.filt = flowfilter.parse(ctx.options.save_stream_filter)\n                if not self.filt:\n                    raise exceptions.OptionsError(\n                        \"Invalid filter specification: %s\" % ctx.options.save_stream_filter\n                    )\n            else:\n                self.filt = None\n        if \"save_stream_file\" in updated or \"save_stream_filter\" in updated:\n            if self.stream:\n                self.done()\n            if ctx.options.save_stream_file:\n                self.start_stream_to_path(ctx.options.save_stream_file, self.filt)\n\n    def save(self, flows: typing.Sequence[flow.Flow], path: str) -> None:\n        \"\"\"\n            Save flows to a file. If the path starts with a +, flows are\n            appended to the file, otherwise it is over-written.\n        \"\"\"\n        try:\n            f = self.open_file(path)\n        except IOError as v:\n            raise exceptions.CommandError(v) from v\n        stream = io.FlowWriter(f)\n        for i in flows:\n            stream.add(i)\n        f.close()\n        ctx.log.alert(\"Saved %s flows.\" % len(flows))\n\n    def load(self, l):\n        l.add_command(\"save.file\", self.save)\n\n    def tcp_start(self, flow):\n        if self.stream:\n            self.active_flows.add(flow)\n\n    def tcp_end(self, flow):\n        if self.stream:\n            self.stream.add(flow)\n            self.active_flows.discard(flow)\n\n    def response(self, flow):\n        if self.stream:\n            self.stream.add(flow)\n            self.active_flows.discard(flow)\n\n    def request(self, flow):\n        if self.stream:\n            self.active_flows.add(flow)\n\n    def done(self):\n        if self.stream:\n            for f in self.active_flows:\n                self.stream.add(f)\n            self.active_flows = set([])\n            self.stream.fo.close()\n            self.stream = None\n", "path": "mitmproxy/addons/save.py"}]}