prompt: 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()
  
  ```
  
golden_diff: 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):
  
verification_info: {"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"}]}