From 5e7f3c86c04b6396a50451a10bcc39c048bf1a91 Mon Sep 17 00:00:00 2001 From: Robert Xiao Date: Tue, 3 May 2022 17:45:22 -0700 Subject: [PATCH 1/2] Fix terminal breakage if an error occurs at startup. sys.exit() causes a CancelledError to be thrown. ErrorCheck._shutdown_if_errored fires sys.exit after self.running() returns, causing the CancelledError to appear in Event.wait() and preventing Master.done() from being called. This can result in terminal breakage when using the CLI, and is especially apparent if any errors occur during startup (e.g. port is not available, script has a syntax error, etc.). The fix is simply to ensure that Master.done always gets called. --- mitmproxy/master.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/mitmproxy/master.py b/mitmproxy/master.py index 3925602ad..ec10032c0 100644 --- a/mitmproxy/master.py +++ b/mitmproxy/master.py @@ -46,9 +46,11 @@ class Master: # Handle scheduled tasks (configure()) first. await asyncio.sleep(0) await self.running() - await self.should_exit.wait() - - await self.done() + try: + await self.should_exit.wait() + finally: + # .wait might be cancelled (e.g. by sys.exit) + await self.done() finally: self.event_loop.set_exception_handler(old_handler) From 58c13ef432a5409d494134f642f03db4f3e83238 Mon Sep 17 00:00:00 2001 From: Robert Xiao Date: Tue, 3 May 2022 19:07:35 -0700 Subject: [PATCH 2/2] Print out multiple errors from errorcheck If multiple errors occur, it is better to log them all, rather than silently discard all but the first error. --- mitmproxy/addons/errorcheck.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/mitmproxy/addons/errorcheck.py b/mitmproxy/addons/errorcheck.py index 4143a172c..6669ee435 100644 --- a/mitmproxy/addons/errorcheck.py +++ b/mitmproxy/addons/errorcheck.py @@ -1,6 +1,5 @@ import asyncio import sys -from typing import Optional from mitmproxy import log @@ -9,12 +8,12 @@ class ErrorCheck: """Monitor startup for error log entries, and terminate immediately if there are some.""" def __init__(self, log_to_stderr: bool = False): - self.has_errored: Optional[str] = None + self.has_errored: list[str] = [] self.log_to_stderr = log_to_stderr def add_log(self, e: log.LogEntry): - if not self.has_errored and e.level == "error": - self.has_errored = e.msg + if e.level == "error": + self.has_errored.append(e.msg) async def running(self): # don't run immediately, wait for all logging tasks to finish. @@ -23,5 +22,8 @@ class ErrorCheck: async def _shutdown_if_errored(self): if self.has_errored: if self.log_to_stderr: - print(f"Error on startup: {self.has_errored}", file=sys.stderr) + plural = "s" if len(self.has_errored) > 1 else "" + msg = "\n".join(self.has_errored) + print(f"Error{plural} on startup: {msg}", file=sys.stderr) + sys.exit(1)