bpo-35474: Fix mimetypes.guess_all_extensions() potentially mutating list (GH-28286) (GH-28289)

* Calling guess_all_extensions() with strict=False potentially
  mutated types_map_inv.
* Mutating the result of guess_all_extensions() mutated types_map_inv.
(cherry picked from commit 97ea18eced)

Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
This commit is contained in:
Miss Islington (bot) 2021-09-13 10:24:29 -07:00 committed by GitHub
parent 2f1d9bca14
commit 06c26f4d29
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 20 additions and 8 deletions

View file

@ -175,7 +175,7 @@ class MimeTypes:
but non-standard types.
"""
type = type.lower()
extensions = self.types_map_inv[True].get(type, [])
extensions = list(self.types_map_inv[True].get(type, []))
if not strict:
for ext in self.types_map_inv[False].get(type, []):
if ext not in extensions:

View file

@ -113,20 +113,29 @@ class MimeTypesTestCase(unittest.TestCase):
eq(self.db.guess_type(r" \"\`;b&b&c |.tar.gz"), gzip_expected)
def test_guess_all_types(self):
eq = self.assertEqual
unless = self.assertTrue
# First try strict. Use a set here for testing the results because if
# test_urllib2 is run before test_mimetypes, global state is modified
# such that the 'all' set will have more items in it.
all = set(self.db.guess_all_extensions('text/plain', strict=True))
unless(all >= set(['.bat', '.c', '.h', '.ksh', '.pl', '.txt']))
all = self.db.guess_all_extensions('text/plain', strict=True)
self.assertTrue(set(all) >= {'.bat', '.c', '.h', '.ksh', '.pl', '.txt'})
self.assertEqual(len(set(all)), len(all)) # no duplicates
# And now non-strict
all = self.db.guess_all_extensions('image/jpg', strict=False)
all.sort()
eq(all, ['.jpg'])
self.assertEqual(all, ['.jpg'])
# And now for no hits
all = self.db.guess_all_extensions('image/jpg', strict=True)
eq(all, [])
self.assertEqual(all, [])
# And now for type existing in both strict and non-strict mappings.
self.db.add_type('test-type', '.strict-ext')
self.db.add_type('test-type', '.non-strict-ext', strict=False)
all = self.db.guess_all_extensions('test-type', strict=False)
self.assertEqual(all, ['.strict-ext', '.non-strict-ext'])
all = self.db.guess_all_extensions('test-type')
self.assertEqual(all, ['.strict-ext'])
# Test that changing the result list does not affect the global state
all.append('.no-such-ext')
all = self.db.guess_all_extensions('test-type')
self.assertNotIn('.no-such-ext', all)
def test_encoding(self):
getpreferredencoding = locale.getpreferredencoding

View file

@ -0,0 +1,3 @@
Calling :func:`mimetypes.guess_all_extensions` with ``strict=False`` no
longer affects the result of the following call with ``strict=True``.
Also, mutating the returned list no longer affects the global state.