From 52a2675ae8aec5fe786be4444afdffe7facc3484 Mon Sep 17 00:00:00 2001 From: Xavier-Do Date: Wed, 3 Apr 2024 11:33:51 +0200 Subject: [PATCH] [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 --- addons/web/tests/test_image.py | 79 ++++++++++++------- .../tests/test_slide_resource.py | 8 +- 2 files changed, 54 insertions(+), 33 deletions(-) diff --git a/addons/web/tests/test_image.py b/addons/web/tests/test_image.py index 943ddeded4c..6ebdb99f956 100644 --- a/addons/web/tests/test_image.py +++ b/addons/web/tests/test_image.py @@ -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""", + ) diff --git a/addons/website_slides/tests/test_slide_resource.py b/addons/website_slides/tests/test_slide_resource.py index 1e9b5ca69aa..08be6c6276b 100644 --- a/addons/website_slides/tests/test_slide_resource.py +++ b/addons/website_slides/tests/test_slide_resource.py @@ -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)