mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-06-17 10:15:27 -04:00
fix(email): guarantee IMAP conn.logout() on all exception paths (#1530)
Three IMAP connection leaks were recently fixed via try/finally (#1325, #1330, #1423). This commit applies the same pattern to the remaining callsites that still used inline logout-only cleanup. routes/email_helpers.py: - _fetch_sender_thread_context: conn was uninitialized when the outer try/except returned early on connect failure, causing the finally block to crash on conn.close()/conn.logout(). Merged the two separate try blocks into one and added conn=None guard. - _pre_retrieve_context: ctx_conn.logout() was inside the loop body with no finally, so any exception in the folder/search loop leaked the socket. Moved cleanup into a finally block with ctx_conn=None guard. mcp_servers/email_server.py: - _list_emails: multiple inline conn.logout() calls on early-return paths; exception between them leaked the socket. Wrapped in try/finally. - _read_email: same pattern — four separate logout() calls replaced by a single finally block. - _reply_to_email: logout() called before the error check, so an exception in conn.select() leaked the socket. Wrapped in try/finally. - _download_attachment: same pattern as _reply_to_email. Also adds tests/test_imap_leak_fixes.py with 9 regression tests (one per function/failure-mode) that monkeypatch _imap_connect and assert conn.logout() is called exactly once even when IMAP operations raise.
This commit is contained in:
+13
-13
@@ -1140,13 +1140,9 @@ def _fetch_sender_thread_context(sender_addr: str,
|
||||
if exclude_uid:
|
||||
seen_uids.add((exclude_folder or "INBOX", str(exclude_uid)))
|
||||
|
||||
conn = None
|
||||
try:
|
||||
conn = _imap_connect(account_id, owner=owner)
|
||||
except Exception as e:
|
||||
logger.warning(f"sender-thread-context: imap connect failed: {e}")
|
||||
return ""
|
||||
|
||||
try:
|
||||
for folder in ["INBOX", "Sent", "Archive", "Drafts"]:
|
||||
if len(blocks) >= limit:
|
||||
break
|
||||
@@ -1213,11 +1209,14 @@ def _fetch_sender_thread_context(sender_addr: str,
|
||||
if atts_text:
|
||||
lines.append(atts_text)
|
||||
blocks.append("\n".join(lines))
|
||||
except Exception as e:
|
||||
logger.warning(f"sender-thread-context: imap failed: {e}")
|
||||
finally:
|
||||
try: conn.close()
|
||||
except Exception: pass
|
||||
try: conn.logout()
|
||||
except Exception: pass
|
||||
if conn:
|
||||
try: conn.close()
|
||||
except Exception: pass
|
||||
try: conn.logout()
|
||||
except Exception: pass
|
||||
|
||||
if not blocks:
|
||||
return ""
|
||||
@@ -1320,6 +1319,7 @@ def _pre_retrieve_context(
|
||||
if not terms_list:
|
||||
return context_snippets, terms_list
|
||||
|
||||
ctx_conn = None
|
||||
try:
|
||||
ctx_conn = _imap_connect(account_id, owner=owner)
|
||||
for folder in ["INBOX", "Sent", "Archive", "Drafts"]:
|
||||
@@ -1356,12 +1356,12 @@ def _pre_retrieve_context(
|
||||
except Exception as _e:
|
||||
logger.warning(f" search {folder} {term!r} failed: {_e}")
|
||||
continue
|
||||
try:
|
||||
ctx_conn.logout()
|
||||
except Exception:
|
||||
pass
|
||||
except Exception as _e:
|
||||
logger.warning(f"IMAP context search failed: {_e}")
|
||||
finally:
|
||||
if ctx_conn:
|
||||
try: ctx_conn.logout()
|
||||
except Exception: pass
|
||||
|
||||
try:
|
||||
from routes.contacts_routes import _fetch_contacts
|
||||
|
||||
Reference in New Issue
Block a user