From 52d7579435c1419f94288155f8a8e63a8759faa3 Mon Sep 17 00:00:00 2001 From: Julien Castiaux Date: Wed, 21 Feb 2024 12:49:33 +0100 Subject: [PATCH] [FIX] base: serve_fallback infinite redirection Create an attachment with an URL to a static file that does not exists, e.g. '/web/static/idontexist.png'. Inside your browser try to access that file, open . The browser fails with a "Too Many Redirections" error. When a path is not found, nor in the static files, nor in the controllers, `_serve_fallback` kicks in and attempt to find a resource outside of the router that matches the URL. In case it finds an attachment with a matching URL, it'll deliver it. In this specific case, it finds our attachment and return a redirection to it's URL, which is the same URL as the request hence it loops back. Don't deliver URL attachments via `_serve_fallback`, only deliver stored files. closes odoo/odoo#156323 X-original-commit: d2bea592db6a66d531b83437d42b273606f629f1 Signed-off-by: Julien Castiaux (juc) --- odoo/addons/base/models/ir_http.py | 2 +- odoo/addons/test_http/tests/test_static.py | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/odoo/addons/base/models/ir_http.py b/odoo/addons/base/models/ir_http.py index 8a6447a4099..d63ec1400a6 100644 --- a/odoo/addons/base/models/ir_http.py +++ b/odoo/addons/base/models/ir_http.py @@ -240,7 +240,7 @@ class IrHttp(models.AbstractModel): def _serve_fallback(cls): model = request.env['ir.attachment'] attach = model.sudo()._get_serve_attachment(request.httprequest.path) - if attach: + if attach and (attach.store_fname or attach.db_datas): return Stream.from_attachment(attach).get_response() @classmethod diff --git a/odoo/addons/test_http/tests/test_static.py b/odoo/addons/test_http/tests/test_static.py index 1e745460a00..bcc07b403c2 100644 --- a/odoo/addons/test_http/tests/test_static.py +++ b/odoo/addons/test_http/tests/test_static.py @@ -6,6 +6,7 @@ from http import HTTPStatus from os.path import basename, join as opj from unittest.mock import patch from freezegun import freeze_time +from urllib3.util import parse_url import odoo from odoo.tests import new_test_user, tagged, RecordCapturer @@ -311,6 +312,22 @@ class TestHttpStatic(TestHttpStaticCommon): self.assertFalse(att.checksum) self.assertDownloadGizeh(f'/web/image/{att.id}') + def test_static19_fallback_redirection_loop(self): + bad_path = '/test_http/static/idontexist.png' + self.assertRaises(FileNotFoundError, file_open, bad_path[1:]) + + self.env['ir.attachment'].create({ + 'name': 'idontexist.png', + 'mimetype': 'image/png', + 'url': bad_path, + 'public': True, + }) + + res = self.url_open(bad_path, allow_redirects=False) + location = parse_url(res.headers.get('Location', '')) + self.assertNotEqual(location.path, bad_path, "loop detected") + self.assertEqual(res.status_code, 404) + @tagged('post_install', '-at_install') class TestHttpStaticLogo(TestHttpStaticCommon):