We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Mitmdump does not exit
#### Problem Description
Mitmdump does not exit automatically when executing:

`mitmdump -nr infile -w outfile
`

Until version 10.0.0 it was working properly and when running mitmdump with "-n" the process finished automatically once the outfile was written.

#### Steps to reproduce the behavior:
1. Generate a mitm file
2. Execute mitmdump -nr infile -w outfile

#### System Information
Mitmproxy: 10.3.0 binary
Python:    3.12.3
OpenSSL:   OpenSSL 3.2.1 30 Jan 2024
Platform:  Linux-6.5.0-27-generic-x86_64-with-glibc2.35


--- 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/readfile.py`
Content:
```
1 import asyncio
2 import logging
3 import os.path
4 import sys
5 from typing import BinaryIO
6 from typing import Optional
7 
8 from mitmproxy import command
9 from mitmproxy import ctx
10 from mitmproxy import exceptions
11 from mitmproxy import flowfilter
12 from mitmproxy import io
13 
14 logger = logging.getLogger(__name__)
15 
16 
17 class ReadFile:
18     """
19     An addon that handles reading from file on startup.
20     """
21 
22     def __init__(self):
23         self.filter = None
24         self._read_task: asyncio.Task | None = None
25 
26     def load(self, loader):
27         loader.add_option("rfile", Optional[str], None, "Read flows from file.")
28         loader.add_option(
29             "readfile_filter", Optional[str], None, "Read only matching flows."
30         )
31 
32     def configure(self, updated):
33         if "readfile_filter" in updated:
34             if ctx.options.readfile_filter:
35                 try:
36                     self.filter = flowfilter.parse(ctx.options.readfile_filter)
37                 except ValueError as e:
38                     raise exceptions.OptionsError(str(e)) from e
39             else:
40                 self.filter = None
41 
42     async def load_flows(self, fo: BinaryIO) -> int:
43         cnt = 0
44         freader = io.FlowReader(fo)
45         try:
46             for flow in freader.stream():
47                 if self.filter and not self.filter(flow):
48                     continue
49                 await ctx.master.load_flow(flow)
50                 cnt += 1
51         except (OSError, exceptions.FlowReadException) as e:
52             if cnt:
53                 logging.warning("Flow file corrupted - loaded %i flows." % cnt)
54             else:
55                 logging.error("Flow file corrupted.")
56             raise exceptions.FlowReadException(str(e)) from e
57         else:
58             return cnt
59 
60     async def load_flows_from_path(self, path: str) -> int:
61         path = os.path.expanduser(path)
62         try:
63             with open(path, "rb") as f:
64                 return await self.load_flows(f)
65         except OSError as e:
66             logging.error(f"Cannot load flows: {e}")
67             raise exceptions.FlowReadException(str(e)) from e
68 
69     async def doread(self, rfile: str) -> None:
70         try:
71             await self.load_flows_from_path(rfile)
72         except exceptions.FlowReadException as e:
73             logger.exception(f"Failed to read {ctx.options.rfile}: {e}")
74         finally:
75             self._read_task = None
76 
77     def running(self):
78         if ctx.options.rfile:
79             self._read_task = asyncio.create_task(self.doread(ctx.options.rfile))
80 
81     @command.command("readfile.reading")
82     def reading(self) -> bool:
83         return bool(self._read_task)
84 
85 
86 class ReadFileStdin(ReadFile):
87     """Support the special case of "-" for reading from stdin"""
88 
89     async def load_flows_from_path(self, path: str) -> int:
90         if path == "-":  # pragma: no cover
91             # Need to think about how to test this. This function is scheduled
92             # onto the event loop, where a sys.stdin mock has no effect.
93             return await self.load_flows(sys.stdin.buffer)
94         else:
95             return await super().load_flows_from_path(path)
96
```
--- 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/readfile.py b/mitmproxy/addons/readfile.py
--- a/mitmproxy/addons/readfile.py
+++ b/mitmproxy/addons/readfile.py
@@ -71,8 +71,6 @@
             await self.load_flows_from_path(rfile)
         except exceptions.FlowReadException as e:
             logger.exception(f"Failed to read {ctx.options.rfile}: {e}")
-        finally:
-            self._read_task = None
 
     def running(self):
         if ctx.options.rfile:
@@ -80,7 +78,7 @@
 
     @command.command("readfile.reading")
     def reading(self) -> bool:
-        return bool(self._read_task)
+        return bool(self._read_task and not self._read_task.done())
 
 
 class ReadFileStdin(ReadFile):

{"golden_diff": "diff --git a/mitmproxy/addons/readfile.py b/mitmproxy/addons/readfile.py\n--- a/mitmproxy/addons/readfile.py\n+++ b/mitmproxy/addons/readfile.py\n@@ -71,8 +71,6 @@\n             await self.load_flows_from_path(rfile)\n         except exceptions.FlowReadException as e:\n             logger.exception(f\"Failed to read {ctx.options.rfile}: {e}\")\n-        finally:\n-            self._read_task = None\n \n     def running(self):\n         if ctx.options.rfile:\n@@ -80,7 +78,7 @@\n \n     @command.command(\"readfile.reading\")\n     def reading(self) -> bool:\n-        return bool(self._read_task)\n+        return bool(self._read_task and not self._read_task.done())\n \n \n class ReadFileStdin(ReadFile):\n", "issue": "Mitmdump does not exit\n#### Problem Description\r\nMitmdump does not exit automatically when executing:\r\n\r\n`mitmdump -nr infile -w outfile\r\n`\r\n\r\nUntil version 10.0.0 it was working properly and when running mitmdump with \"-n\" the process finished automatically once the outfile was written.\r\n\r\n#### Steps to reproduce the behavior:\r\n1. Generate a mitm file\r\n2. Execute mitmdump -nr infile -w outfile\r\n\r\n#### System Information\r\nMitmproxy: 10.3.0 binary\r\nPython:    3.12.3\r\nOpenSSL:   OpenSSL 3.2.1 30 Jan 2024\r\nPlatform:  Linux-6.5.0-27-generic-x86_64-with-glibc2.35\r\n\n", "before_files": [{"content": "import asyncio\nimport logging\nimport os.path\nimport sys\nfrom typing import BinaryIO\nfrom typing import Optional\n\nfrom mitmproxy import command\nfrom mitmproxy import ctx\nfrom mitmproxy import exceptions\nfrom mitmproxy import flowfilter\nfrom mitmproxy import io\n\nlogger = logging.getLogger(__name__)\n\n\nclass ReadFile:\n    \"\"\"\n    An addon that handles reading from file on startup.\n    \"\"\"\n\n    def __init__(self):\n        self.filter = None\n        self._read_task: asyncio.Task | None = None\n\n    def load(self, loader):\n        loader.add_option(\"rfile\", Optional[str], None, \"Read flows from file.\")\n        loader.add_option(\n            \"readfile_filter\", Optional[str], None, \"Read only matching flows.\"\n        )\n\n    def configure(self, updated):\n        if \"readfile_filter\" in updated:\n            if ctx.options.readfile_filter:\n                try:\n                    self.filter = flowfilter.parse(ctx.options.readfile_filter)\n                except ValueError as e:\n                    raise exceptions.OptionsError(str(e)) from e\n            else:\n                self.filter = None\n\n    async def load_flows(self, fo: BinaryIO) -> int:\n        cnt = 0\n        freader = io.FlowReader(fo)\n        try:\n            for flow in freader.stream():\n                if self.filter and not self.filter(flow):\n                    continue\n                await ctx.master.load_flow(flow)\n                cnt += 1\n        except (OSError, exceptions.FlowReadException) as e:\n            if cnt:\n                logging.warning(\"Flow file corrupted - loaded %i flows.\" % cnt)\n            else:\n                logging.error(\"Flow file corrupted.\")\n            raise exceptions.FlowReadException(str(e)) from e\n        else:\n            return cnt\n\n    async def load_flows_from_path(self, path: str) -> int:\n        path = os.path.expanduser(path)\n        try:\n            with open(path, \"rb\") as f:\n                return await self.load_flows(f)\n        except OSError as e:\n            logging.error(f\"Cannot load flows: {e}\")\n            raise exceptions.FlowReadException(str(e)) from e\n\n    async def doread(self, rfile: str) -> None:\n        try:\n            await self.load_flows_from_path(rfile)\n        except exceptions.FlowReadException as e:\n            logger.exception(f\"Failed to read {ctx.options.rfile}: {e}\")\n        finally:\n            self._read_task = None\n\n    def running(self):\n        if ctx.options.rfile:\n            self._read_task = asyncio.create_task(self.doread(ctx.options.rfile))\n\n    @command.command(\"readfile.reading\")\n    def reading(self) -> bool:\n        return bool(self._read_task)\n\n\nclass ReadFileStdin(ReadFile):\n    \"\"\"Support the special case of \"-\" for reading from stdin\"\"\"\n\n    async def load_flows_from_path(self, path: str) -> int:\n        if path == \"-\":  # pragma: no cover\n            # Need to think about how to test this. This function is scheduled\n            # onto the event loop, where a sys.stdin mock has no effect.\n            return await self.load_flows(sys.stdin.buffer)\n        else:\n            return await super().load_flows_from_path(path)\n", "path": "mitmproxy/addons/readfile.py"}], "after_files": [{"content": "import asyncio\nimport logging\nimport os.path\nimport sys\nfrom typing import BinaryIO\nfrom typing import Optional\n\nfrom mitmproxy import command\nfrom mitmproxy import ctx\nfrom mitmproxy import exceptions\nfrom mitmproxy import flowfilter\nfrom mitmproxy import io\n\nlogger = logging.getLogger(__name__)\n\n\nclass ReadFile:\n    \"\"\"\n    An addon that handles reading from file on startup.\n    \"\"\"\n\n    def __init__(self):\n        self.filter = None\n        self._read_task: asyncio.Task | None = None\n\n    def load(self, loader):\n        loader.add_option(\"rfile\", Optional[str], None, \"Read flows from file.\")\n        loader.add_option(\n            \"readfile_filter\", Optional[str], None, \"Read only matching flows.\"\n        )\n\n    def configure(self, updated):\n        if \"readfile_filter\" in updated:\n            if ctx.options.readfile_filter:\n                try:\n                    self.filter = flowfilter.parse(ctx.options.readfile_filter)\n                except ValueError as e:\n                    raise exceptions.OptionsError(str(e)) from e\n            else:\n                self.filter = None\n\n    async def load_flows(self, fo: BinaryIO) -> int:\n        cnt = 0\n        freader = io.FlowReader(fo)\n        try:\n            for flow in freader.stream():\n                if self.filter and not self.filter(flow):\n                    continue\n                await ctx.master.load_flow(flow)\n                cnt += 1\n        except (OSError, exceptions.FlowReadException) as e:\n            if cnt:\n                logging.warning(\"Flow file corrupted - loaded %i flows.\" % cnt)\n            else:\n                logging.error(\"Flow file corrupted.\")\n            raise exceptions.FlowReadException(str(e)) from e\n        else:\n            return cnt\n\n    async def load_flows_from_path(self, path: str) -> int:\n        path = os.path.expanduser(path)\n        try:\n            with open(path, \"rb\") as f:\n                return await self.load_flows(f)\n        except OSError as e:\n            logging.error(f\"Cannot load flows: {e}\")\n            raise exceptions.FlowReadException(str(e)) from e\n\n    async def doread(self, rfile: str) -> None:\n        try:\n            await self.load_flows_from_path(rfile)\n        except exceptions.FlowReadException as e:\n            logger.exception(f\"Failed to read {ctx.options.rfile}: {e}\")\n\n    def running(self):\n        if ctx.options.rfile:\n            self._read_task = asyncio.create_task(self.doread(ctx.options.rfile))\n\n    @command.command(\"readfile.reading\")\n    def reading(self) -> bool:\n        return bool(self._read_task and not self._read_task.done())\n\n\nclass ReadFileStdin(ReadFile):\n    \"\"\"Support the special case of \"-\" for reading from stdin\"\"\"\n\n    async def load_flows_from_path(self, path: str) -> int:\n        if path == \"-\":  # pragma: no cover\n            # Need to think about how to test this. This function is scheduled\n            # onto the event loop, where a sys.stdin mock has no effect.\n            return await self.load_flows(sys.stdin.buffer)\n        else:\n            return await super().load_flows_from_path(path)\n", "path": "mitmproxy/addons/readfile.py"}]}