From e5cc17323d0c93a451bf0d718cdec5bcdc75e890 Mon Sep 17 00:00:00 2001 From: Julien Castiaux Date: Wed, 22 Nov 2023 17:08:27 +0100 Subject: [PATCH] [FIX] http_routing: error occurs if the path is not "latin1" string MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For multi language website, when request http:/localhost/en/something, Odoo reroutes from the requested path /en/something to the new path /something with lang=en_US in context. If the new path is a unicode string like http:/localhost/vi/xin-chào, http:/localhost/ru/привет, a error should occur at werkzeug._compat.wsgi_decoding_dance() because the path was not latin1 string. The utf-8 encoding followed by a latin-1 decoding is required by the WSGI specification[^1]. latin-1 is used as an encoding passthrought: that encoding has a representation for all the 256 bytes, i.e. it is impossible that decoding a text will raise a ValueError. The WSGI spec uses this trick to save values until the actual charset (present in the Content-Type header) in known. [^1]: https://peps.python.org/pep-3333/#a-note-on-string-types closes odoo/odoo#143898 X-original-commit: 9b69b87c08b1d62b3581fe651bee692a4f217dff Signed-off-by: Julien Castiaux (juc) --- addons/http_routing/models/ir_http.py | 5 +++++ addons/website/tests/test_lang_url.py | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/addons/http_routing/models/ir_http.py b/addons/http_routing/models/ir_http.py index 9ba68b5e0d5..b2a0ae131f3 100644 --- a/addons/http_routing/models/ir_http.py +++ b/addons/http_routing/models/ir_http.py @@ -518,6 +518,11 @@ class IrHttp(models.AbstractModel): string. This act as a light redirection, it does not return a 3xx responses to the browser but still change the current URL. """ + # WSGI encoding dance https://peps.python.org/pep-3333/#unicode-issues + if isinstance(path, str): + path = path.encode('utf-8') + path = path.decode('latin1', 'replace') + if query_string is None: query_string = request.httprequest.environ['QUERY_STRING'] diff --git a/addons/website/tests/test_lang_url.py b/addons/website/tests/test_lang_url.py index b4a49b1db20..1daad1e52eb 100644 --- a/addons/website/tests/test_lang_url.py +++ b/addons/website/tests/test_lang_url.py @@ -99,6 +99,13 @@ class TestLangUrl(HttpCase): [anchor] = doc.xpath('//a[@id="foo"]') self.assertEqual(anchor.get('href'), 'http://]', 'The invalid IP URL must be left untouched') + def test_06_reroute_unicode(self): + res = self.url_open('/fr/привет') + self.assertEqual(res.status_code, 404, "Rerouting didn't crash because of unicode path") + + res = self.url_open('/fr/path?привет=1') + self.assertEqual(res.status_code, 404, "Rerouting didn't crash because of unicode query-string") + @tagged('-at_install', 'post_install') class TestControllerRedirect(TestLangUrl):