Repository: mitmproxy/mitmproxy

Issue:
mailcap deprecated for Python 3.11 removed for Python 3.13
I've been following this Python dev mailing thread which proposed to deprecate `mailcap` from the standard library: https://mail.python.org/archives/list/python-dev@python.org/thread/EB2BS4DBWSTBIOPQL5QTBSIOBORWSCMJ/

After a code search I noticed that you were the only library I recognized which used this module: 
https://grep.app/search?q=import%20mailcap
https://github.com/mitmproxy/mitmproxy/blob/4f7f64c516341c586c9f8cb6593217ff3e359351/mitmproxy/tools/console/master.py#L2

Please be aware the Steering Council just accepted this deprecation proposal meaning the module will be deprecated for Python 3.11 removed for Python 3.13.

(I don't have any affiliation with this decision, I am just trying to proactively raise awareness)


Discussion:
Thanks for the heads-up! 😃

I think this is a very reasonable deprecation and deprecation schedule, we can easily work around this on our end. :)
@mhils Are you aware of any library that could substitute `mailcap`, what's your idea here? I poked around this, and it seems that it is used in only one place for opening a request/response in default application (if content type is correctly recognized), but it works only on Unix-compatible OSes as `mailcap` uses `*/etc/*` files for detection:

https://github.com/python/cpython/blob/f6656163de483003697d510031827b7512056d55/Lib/mailcap.py#L51-L65

So on macOS (which I use) and Windows mitmproxy falls back to `less` or other editor:

https://github.com/mitmproxy/mitmproxy/blob/9d1821e920d6225578a0b65881d203a537186298/mitmproxy/tools/console/master.py#L160-L175

The easiest solution would be to just have `less` or other pager open a file, but I'm not sure if you want to kind of degrade the feature on Unix OSes.
@KORraNpl: I had not heard about/used mailcap before this issue was opened, so I naturally have no idea. I traced it back to https://github.com/mitmproxy/mitmproxy/commit/cb0e3287090786fad566feb67ac07b8ef361b2c3 though (Feb 2010), so that was quite fun. 😄 

Honestly I feel like there isn't much harm done if we just remove that part. 

There's of course opportunity to improve things, maybe `xdg-open` on Linux or `os.startfile(..., "edit")` on Windows? We do need to think critically about whether we want to essentially enable code execution here, so maybe just removing it is good enough.

Resolving patch:
diff --git a/mitmproxy/tools/console/master.py b/mitmproxy/tools/console/master.py
--- a/mitmproxy/tools/console/master.py
+++ b/mitmproxy/tools/console/master.py
@@ -1,5 +1,4 @@
 import asyncio
-import mailcap
 import mimetypes
 import os
 import os.path
@@ -154,28 +153,20 @@ def spawn_external_viewer(self, data, contenttype):
         # read-only to remind the user that this is a view function
         os.chmod(name, stat.S_IREAD)
 
-        cmd = None
-        shell = False
+        # hm which one should get priority?
+        c = (
+            os.environ.get("MITMPROXY_EDITOR")
+            or os.environ.get("PAGER")
+            or os.environ.get("EDITOR")
+        )
+        if not c:
+            c = "less"
+        cmd = shlex.split(c)
+        cmd.append(name)
 
-        if contenttype:
-            c = mailcap.getcaps()
-            cmd, _ = mailcap.findmatch(c, contenttype, filename=name)
-            if cmd:
-                shell = True
-        if not cmd:
-            # hm which one should get priority?
-            c = (
-                os.environ.get("MITMPROXY_EDITOR")
-                or os.environ.get("PAGER")
-                or os.environ.get("EDITOR")
-            )
-            if not c:
-                c = "less"
-            cmd = shlex.split(c)
-            cmd.append(name)
         with self.uistopped():
             try:
-                subprocess.call(cmd, shell=shell)
+                subprocess.call(cmd, shell=False)
             except:
                 signals.status_message.send(
                     message="Can't start external viewer: %s" % " ".join(c)


Test patch: