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()

```

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:

{"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"}]}