[IMP] web: protect _rpc calls on destroyed widgets
It might happen that some code in a widget (callbacks given to other function calls) is executed after the widget's destruction. For example, trigger an event up with a callback in option, the event is handled by a parent that performs an rpc, meanwhile, the child widget is destroyed, then, the rpc returns and the parent executes the callback. This shouldn't happen, because it means that the callback is executed for nothing. Worst, it crashes if the function _rpc is called inside the callback, because the widget being destroyed, there is no parent to handle the request, and _rpc thus returns undefined. This rev. protects the code from crashing by making _rpc return a pending deferred instead of undefined.
This commit is contained in:
@@ -447,15 +447,17 @@ var ServicesMixin = {
|
||||
return result;
|
||||
},
|
||||
/**
|
||||
* Build a RPC query
|
||||
* Builds and executes RPC query. Returns a deferred's promise resolved with
|
||||
* the RPC result.
|
||||
*
|
||||
* @param {string} arg1 either a route or a model
|
||||
* @param {string} method if a model is given, this argument is a method
|
||||
* @returns {RPCBuilder}
|
||||
* @returns {Deferred's Promise}
|
||||
*/
|
||||
_rpc: function (params, options) {
|
||||
var query = rpc.buildQuery(params);
|
||||
return this.call('ajax', 'rpc', query.route, query.params, options);
|
||||
var def = this.call('ajax', 'rpc', query.route, query.params, options);
|
||||
return def ? def.promise() : $.Deferred().promise();
|
||||
},
|
||||
loadFieldView: function (dataset, view_id, view_type, options) {
|
||||
return this.loadViews(dataset.model, dataset.get_context(), [[view_id, view_type]], options).then(function (result) {
|
||||
|
||||
@@ -377,6 +377,19 @@ QUnit.module('core', {}, function () {
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
QUnit.test("calling _rpc on destroyed widgets", function (assert) {
|
||||
assert.expect(1);
|
||||
|
||||
var widget = new Widget();
|
||||
widget.destroy();
|
||||
widget._rpc({route: '/a/route'}).always(function () {
|
||||
throw Error("Calling _rpc on a destroyed widget should return a " +
|
||||
"deferred that is never resolved nor rejected");
|
||||
});
|
||||
assert.ok(true,
|
||||
"there should be no crash when calling _rpc on a destroyed widget");
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
Reference in New Issue
Block a user