[FIX] web: more robust test_image filename

The main purpose of this test is to ensure that line return are removed,
but all other special character are kept once the file is saved.

Unfortunately, werkzeug versions have different strategies on how to
quote the filename, removing less special character in latest versions
like after https://github.com/pallets/werkzeug/commit/babfc93b3834bcbb22163442a9af70141bcc5a81

This also changes after the changes that removed werkzeug urls methods
replacing them by urllib, making the behaviour different again.

This commit makes the test more robust by checking that the filename
correspond to the expeted one once unquoted, not comparing the quoted
versions.

Part-of: odoo/odoo#160842
This commit is contained in:
Xavier-Do
2024-04-07 10:03:48 +00:00
parent e531d8ed18
commit 52a2675ae8
2 changed files with 54 additions and 33 deletions
+49 -30
View File
@@ -5,7 +5,7 @@ import io
import base64
from PIL import Image
from werkzeug.urls import url_quote
from werkzeug.urls import url_unquote_plus
from odoo.tests.common import HttpCase, tagged
@@ -99,37 +99,56 @@ class TestImage(HttpCase):
'datas': b'R0lGODdhAQABAIAAAP///////ywAAAAAAQABAAACAkQBADs=',
'name': """fô☺o-l'éb \n a"!r".gif""",
'public': True,
'mimetype': 'image/gif'
'mimetype': 'image/gif',
})
res = self.url_open(f'/web/image/{att.id}')
expected_ufilename = url_quote(att.name.replace('\n', '_').replace('\r', '_'))
self.assertEqual(res.headers['Content-Disposition'], r"""inline; filename="foo-l'eb _ a\"!r\".gif"; filename*=UTF-8''""" + expected_ufilename)
res.raise_for_status()
def assert_filenames(
url,
expected_filename,
expected_filename_star='',
message=r"File that will be saved on disc should have the original filename without \n and \r",
):
res = self.url_open(url)
res.raise_for_status()
if expected_filename_star:
inline, filename, filename_star = res.headers['Content-Disposition'].split('; ')
else:
inline, filename = res.headers['Content-Disposition'].split('; ')
filename_star = ''
res = self.url_open(f'/web/image/{att.id}/custom_invalid_name\nis-ok.gif')
self.assertEqual(res.headers['Content-Disposition'], 'inline; filename=custom_invalid_name_is-ok.gif')
res.raise_for_status()
filename = filename.removeprefix("filename=").strip('"')
filename_star = url_unquote_plus(filename_star.removeprefix("filename*=UTF-8''").strip('"'))
res = self.url_open(f'/web/image/{att.id}/\r\n')
self.assertEqual(res.headers['Content-Disposition'], 'inline; filename=__.gif')
res.raise_for_status()
self.assertEqual(inline, 'inline')
self.assertEqual(filename, expected_filename, message)
self.assertEqual(filename_star, expected_filename_star, message)
res = self.url_open(f'/web/image/{att.id}/你好')
self.assertEqual(res.headers['Content-Disposition'], 'inline; filename=.gif; filename*=UTF-8\'\'%E4%BD%A0%E5%A5%BD.gif')
res.raise_for_status()
res = self.url_open(f'/web/image/{att.id}/%E9%9D%A2%E5%9B%BE.gif')
self.assertEqual(res.headers['Content-Disposition'], 'inline; filename=.gif; filename*=UTF-8\'\'%E9%9D%A2%E5%9B%BE.gif')
res.raise_for_status()
res = self.url_open(f'/web/image/{att.id}/hindi_नमस्ते.gif')
self.assertEqual(res.headers['Content-Disposition'], 'inline; filename=hindi_.gif; filename*=UTF-8\'\'hindi_%E0%A4%A8%E0%A4%AE%E0%A4%B8%E0%A5%8D%E0%A4%A4%E0%A5%87.gif')
res.raise_for_status()
res = self.url_open(f'/web/image/{att.id}/arabic_مرحبا.gif')
self.assertEqual(res.headers['Content-Disposition'], 'inline; filename=arabic_.gif; filename*=UTF-8\'\'arabic_%D9%85%D8%B1%D8%AD%D8%A8%D8%A7.gif')
res.raise_for_status()
res = self.url_open(f'/web/image/{att.id}/4wzb_!!63148-0-t1.jpg_360x1Q75.jpg_.webp')
self.assertEqual(res.headers['Content-Disposition'], 'inline; filename=4wzb_!!63148-0-t1.jpg_360x1Q75.jpg_.webp')
res.raise_for_status()
assert_filenames(f'/web/image/{att.id}',
r"""foo-l'eb _ a\"!r\".gif""",
r"""fô☺o-l'éb _ a"!r".gif""",
)
assert_filenames(f'/web/image/{att.id}/custom_invalid_name\nis-ok.gif',
r"""custom_invalid_name_is-ok.gif""",
)
assert_filenames(f'/web/image/{att.id}/\r\n',
r"""__.gif""",
)
assert_filenames(f'/web/image/{att.id}/你好',
r""".gif""",
r"""你好.gif""",
)
assert_filenames(f'/web/image/{att.id}/%E9%9D%A2%E5%9B%BE.gif',
r""".gif""",
r"""面图.gif""",
)
assert_filenames(f'/web/image/{att.id}/hindi_नमस्ते.gif',
r"""hindi_.gif""",
r"""hindi_नमस्ते.gif""",
)
assert_filenames(f'/web/image/{att.id}/arabic_مرحبا',
r"""arabic_.gif""",
r"""arabic_مرحبا.gif""",
)
assert_filenames(f'/web/image/{att.id}/4wzb_!!63148-0-t1.jpg_360x1Q75.jpg_.webp',
r"""4wzb_!!63148-0-t1.jpg_360x1Q75.jpg_.webp""",
)
@@ -2,7 +2,7 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from psycopg2 import IntegrityError
from werkzeug.urls import url_quote
from werkzeug.urls import url_unquote_plus
from odoo.addons.website_slides.tests import common
from odoo.exceptions import ValidationError
@@ -84,5 +84,7 @@ class TestResources(common.SlidesCase, HttpCase):
):
resource.write({'name': name, 'file_name': file_name})
with self.subTest(name=name, file_name=file_name, expected_download_name=expected_download_name):
self.assertIn(f"filename*=UTF-8''{url_quote(expected_download_name)}",
self.url_open(resource.download_url).headers['Content-Disposition'])
content_disposition = self.url_open(resource.download_url).headers['Content-Disposition']
filename_star = content_disposition.split('; ')[-1]
filename_star = filename_star.removeprefix("""filename*=UTF-8''""")
self.assertEqual(url_unquote_plus(filename_star), expected_download_name)