Skip to content

Commit cf5a343

Browse files
committed
[FIX] http: comply with rfc6265
Werkzeug changed the behavior of url_quote in pallets/werkzeug@babfc93 Which appeared in Werkzeug 2.2.2 used in Debian Bookworm. This change broke at least the export feature in Odoo. In summary, the character set specified by [RFC5987] is more restricted than that of [RFC3986]. So url_quote now allows invalid characters. For example, a filename like `Journal Entry (account.move).xlsx` leads to a crash of the client with Werkzeug 2.2.2. url_quote is not really made to conform to [RFC6266] but we did not find any [RFC6266] escaping tool in the standard library. This commit explicitly specify as unsafe this list of chars. [RFC6266]: https://datatracker.ietf.org/doc/html/rfc6266/ [RFC5987]: https://datatracker.ietf.org/doc/html/rfc5987#section-3.2 [RFC3986]: https://datatracker.ietf.org/doc/html/rfc3986/ [RFC2616]: https://datatracker.ietf.org/doc/html/rfc2616#section-2 closes odoo#139069 Signed-off-by: Julien Castiaux (juc) <[email protected]>
1 parent 4cb18fa commit cf5a343

File tree

2 files changed

+29
-3
lines changed

2 files changed

+29
-3
lines changed

odoo/addons/base/tests/test_ir_http.py

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
# -*- coding: utf-8 -*-
2-
1+
from odoo.http import content_disposition
32
from odoo.tests import common
43
import odoo
54

@@ -154,3 +153,30 @@ def test_ir_http_public_user_image(self):
154153
public_user = self.env.ref('base.public_user')
155154
code, *_ = self.env['ir.http']._binary_record_content(public_user.with_user(public_user), 'image_128')
156155
self.assertEqual(code, 404)
156+
157+
158+
class TestContentDisposition(common.BaseCase):
159+
160+
def test_content_disposition(self):
161+
""" Test that content_disposition filename conforms to RFC 6266, RFC 5987 """
162+
assertions = [
163+
('foo bar.xls', 'foo%20bar.xls', 'Space character'),
164+
('foo(bar).xls', 'foo%28bar%29.xls', 'Parenthesis'),
165+
('foo<bar>.xls', 'foo%3Cbar%3E.xls', 'Angle brackets'),
166+
('foo[bar].xls', 'foo%5Bbar%5D.xls', 'Brackets'),
167+
('foo{bar}.xls', 'foo%7Bbar%7D.xls', 'Curly brackets'),
168+
('[email protected]', 'foo%40bar.xls', 'At sign'),
169+
('foo,bar.xls', 'foo%2Cbar.xls', 'Comma sign'),
170+
('foo;bar.xls', 'foo%3Bbar.xls', 'Semicolon sign'),
171+
('foo:bar.xls', 'foo%3Abar.xls', 'Colon sign'),
172+
('foo\\bar.xls', 'foo%5Cbar.xls', 'Backslash sign'),
173+
('foo"bar.xls', 'foo%22bar.xls', 'Double quote sign'),
174+
('foo/bar.xls', 'foo%2Fbar.xls', 'Slash sign'),
175+
('foo?bar.xls', 'foo%3Fbar.xls', 'Question mark'),
176+
('foo=bar.xls', 'foo%3Dbar.xls', 'Equal sign'),
177+
('foo*bar.xls', 'foo%2Abar.xls', 'Star sign'),
178+
("foo'bar.xls", 'foo%27bar.xls', 'Single-quote sign'),
179+
('foo%bar.xls', 'foo%25bar.xls', 'Percent sign'),
180+
]
181+
for filename, pct_encoded, hint in assertions:
182+
self.assertEqual(content_disposition(filename), f"attachment; filename*=UTF-8''{pct_encoded}", f'{hint} should be percent encoded')

odoo/http.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1689,7 +1689,7 @@ def send_file(filepath_or_fp, mimetype=None, as_attachment=False, filename=None,
16891689

16901690
def content_disposition(filename):
16911691
filename = odoo.tools.ustr(filename)
1692-
escaped = urls.url_quote(filename, safe='')
1692+
escaped = urls.url_quote(filename, safe='', unsafe='()<>@,;:"/[]?={}\\*\'%') # RFC6266
16931693

16941694
return "attachment; filename*=UTF-8''%s" % escaped
16951695

0 commit comments

Comments
 (0)