]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-117807: Handle invalid UTF-8 in mimetypes map files (GH-151216)
authorHarjoth Khara <harjoth.khara@gmail.com>
Tue, 4 Aug 2026 16:47:02 +0000 (09:47 -0700)
committerGitHub <noreply@github.com>
Tue, 4 Aug 2026 16:47:02 +0000 (19:47 +0300)
Lib/mimetypes.py
Lib/test/test_mimetypes.py
Misc/NEWS.d/next/Library/2026-06-10-00-00-01.gh-issue-117807.Cx1178.rst [new file with mode: 0644]

index 4339ef5a61397dd2005af3205dd9b5e86c25a328..1d6b33fe854c9437e51c45ba64f0e7b9da82b0a7 100644 (file)
@@ -250,7 +250,7 @@ class MimeTypes:
         list of standard types, else to the list of non-standard
         types.
         """
-        with open(filename, encoding='utf-8') as fp:
+        with open(filename, encoding='utf-8', errors='surrogateescape') as fp:
             self.readfp(fp, strict)
 
     def readfp(self, fp, strict=True):
@@ -444,7 +444,7 @@ def init(files=None):
 
 def read_mime_types(file):
     try:
-        f = open(file, encoding='utf-8')
+        f = open(file, encoding='utf-8', errors='surrogateescape')
     except OSError:
         return None
     with f:
index 19983fa3fa7628d1134ac95b91b420587c43d9c9..1e0f6664af0d066898fffb04b3bd38e2b5a62b21 100644 (file)
@@ -67,9 +67,50 @@ class MimeTypesModuleTestCase(unittest.TestCase):
         with unittest.mock.patch.object(mimetypes, 'open',
                                         return_value=fp) as mock_open:
             mime_dict = mimetypes.read_mime_types(filename)
-            mock_open.assert_called_with(filename, encoding='utf-8')
+            mock_open.assert_called_with(filename, encoding='utf-8',
+                                         errors='surrogateescape')
         eq(mime_dict[".Français"], "application/no-mans-land")
 
+    def test_read_mime_types_invalid_utf8_comment(self):
+        with os_helper.temp_dir() as directory:
+            data = (b"# non-UTF-8 comment: \x83\n"
+                    b"x-application/x-unittest pyunit\n")
+            file = os.path.join(directory, "sample.mimetype")
+            with open(file, "wb") as f:
+                f.write(data)
+
+            mime_dict = mimetypes.read_mime_types(file)
+            self.assertEqual(
+                mime_dict[".pyunit"], "x-application/x-unittest")
+
+            db = mimetypes.MimeTypes()
+            db.read(file)
+            self.assertEqual(
+                db.guess_file_type("sample.pyunit")[0],
+                "x-application/x-unittest")
+
+            mimetypes.init(files=[file])
+            self.assertEqual(
+                mimetypes.guess_file_type("sample.pyunit")[0],
+                "x-application/x-unittest")
+
+    def test_read_mime_types_invalid_utf8_type(self):
+        # A non-UTF-8 byte in a type or extension (not only in a comment) is
+        # preserved via surrogateescape, so the mapping is not corrupted.
+        with os_helper.temp_dir() as directory:
+            data = (b"x-application/x-unittest pyunit\n"
+                    b"application/bad\x83 badext\x83\n")
+            file = os.path.join(directory, "sample.mimetype")
+            with open(file, "wb") as f:
+                f.write(data)
+
+            bad_type = b"application/bad\x83".decode("utf-8", "surrogateescape")
+            bad_ext = b".badext\x83".decode("utf-8", "surrogateescape")
+
+            mime_dict = mimetypes.read_mime_types(file)
+            self.assertEqual(mime_dict[".pyunit"], "x-application/x-unittest")
+            self.assertEqual(mime_dict[bad_ext], bad_type)
+
     def test_init_reinitializes(self):
         # Issue 4936: make sure an init starts clean
         # First, put some poison into the types table
diff --git a/Misc/NEWS.d/next/Library/2026-06-10-00-00-01.gh-issue-117807.Cx1178.rst b/Misc/NEWS.d/next/Library/2026-06-10-00-00-01.gh-issue-117807.Cx1178.rst
new file mode 100644 (file)
index 0000000..d6a874a
--- /dev/null
@@ -0,0 +1,2 @@
+Fix :mod:`mimetypes` initialization from MIME map files containing invalid
+UTF-8 bytes.