[FIX] core: avoid infinite loop during HTML sanitize
During an onchange, fields read from database are validated again. This causes
an infinite loop with HTML fields since Odoo 16 because we're revalidating a
value we're reading from the database, which triggers a sanitisation check,
which fetches the original value, etc etc.
Even if the functional bug only appears in 16.0 and above, the root cause is
also present in 15.0 so this commit targets 15.0
steps to reproduce (in 16 or next versions):
- Change Marc Demos's access rights Website = Restricted Editor
- Bypass HTML Field Sanitize = Off
- Inventory / Products / Product Variants
- Studio on the Sales tab and add website_description under Website Sequence
- Go to product [E-COM07] Large Cabinet and fill in the newly added website description
- Log out and log in as marc demo
- Navigate back to [E-COM07] Large Cabinet product variant and try to re-order the vendors on the purchase tab
- Error
before this commit:
Error (infinite loop) during onchange
File "/home/nda/dev/odoo/16.0/odoo/odoo/models.py", line 6489, in onchange
record[parent_name]._update_cache({name: record[name]})
File "/home/nda/dev/odoo/16.0/odoo/odoo/models.py", line 5310, in _update_cache
value = field.convert_to_cache(value, self, validate)
File "/home/nda/dev/odoo/16.0/odoo/odoo/fields.py", line 1977, in convert_to_cache
return self._convert(value, record, validate)
File "/home/nda/dev/odoo/16.0/odoo/odoo/fields.py", line 2000, in _convert
original_value = record[self.name]
File "/home/nda/dev/odoo/16.0/odoo/odoo/models.py", line 5897, in __getitem__
return self._fields[key].__get__(self, type(self))
File "/home/nda/dev/odoo/16.0/odoo/odoo/fields.py", line 1198, in __get__
value = self.convert_to_cache(record._origin[self.name], record)
File "/home/nda/dev/odoo/16.0/odoo/odoo/fields.py", line 1977, in convert_to_cache
return self._convert(value, record, validate)
File "/home/nda/dev/odoo/16.0/odoo/odoo/fields.py", line 2000, in _convert
original_value = record[self.name]
...
after this commit:
no error
opw-3575865
X-original-commit: 24d804e
Part-of: odoo/odoo#143307
This commit is contained in:
@@ -3268,6 +3268,36 @@ class TestHtmlField(common.TransactionCase):
|
||||
new_record.invalidate_recordset()
|
||||
new_record.with_user(internal_user).comment5
|
||||
|
||||
@patch('odoo.fields.html_sanitize', return_value='<p>comment</p>')
|
||||
def test_onchange_sanitize(self, patch):
|
||||
self.assertTrue(self.registry['test_new_api.mixed'].comment2.sanitize)
|
||||
|
||||
record = self.env['test_new_api.mixed'].create({
|
||||
'comment2': '<p>comment</p>',
|
||||
})
|
||||
|
||||
# in a perfect world this should be 1, but at the moment the value is
|
||||
# sanitized more than once during creation of the record
|
||||
self.assertEqual(patch.call_count, 3)
|
||||
|
||||
# new value needs to be validated, so it is sanitized once more
|
||||
record.comment2 = '<p>comment</p>'
|
||||
self.assertEqual(patch.call_count, 4)
|
||||
|
||||
# the value is already sanitized for flushing
|
||||
record.flush_recordset()
|
||||
self.assertEqual(patch.call_count, 4)
|
||||
|
||||
# value coming from db does not need to be sanitized
|
||||
record.invalidate_recordset()
|
||||
record.comment2
|
||||
self.assertEqual(patch.call_count, 4)
|
||||
|
||||
# value coming from db during an onchange does not need to be sanitized
|
||||
new_record = record.new(origin=record)
|
||||
new_record.comment2
|
||||
self.assertEqual(patch.call_count, 4)
|
||||
|
||||
|
||||
class TestMagicFields(common.TransactionCase):
|
||||
|
||||
|
||||
+2
-6
@@ -1191,7 +1191,7 @@ class Field(MetaField('DummyField', (object,), {})):
|
||||
|
||||
elif self.store and record._origin and not (self.compute and self.readonly):
|
||||
# new record with origin: fetch from origin
|
||||
value = self.convert_to_cache(record._origin[self.name], record)
|
||||
value = self.convert_to_cache(record._origin[self.name], record, validate=False)
|
||||
env.cache.set(record, self, value)
|
||||
|
||||
elif self.compute: #pylint: disable=using-constant-test
|
||||
@@ -2042,11 +2042,7 @@ class Html(_String):
|
||||
if record.user_has_groups('base.group_sanitize_override'):
|
||||
return value
|
||||
|
||||
# This may cause an infinite recursion when accessing the field on a
|
||||
# new record. Indeed, if record has no value in cache, we default
|
||||
# on the field's value on record._origin and convert it to the
|
||||
# cache format, which ends up here, accessing the field on record!
|
||||
original_value = record[self.name] if record.id else None
|
||||
original_value = record[self.name]
|
||||
if original_value:
|
||||
# Note that sanitize also normalize
|
||||
original_value_sanitized = html_sanitize(original_value, **sanitize_vals)
|
||||
|
||||
Reference in New Issue
Block a user