From 0f9be11ebb33cc2bfaa0e4e92cb7ef85cf791102 Mon Sep 17 00:00:00 2001 From: Dmitry Gozman Date: Wed, 13 Jun 2018 22:40:21 +0000 Subject: [PATCH] [DevTools] Fix DOM Storage with OOPIFs - Collect DOM storages from all targets. - Instantiate InspectorDOMStorage agent for local roots, make it work with InspectedFrames. - Add a test which dumps storage security origins. - Do some origin checks on the frontend to avoid listing "opaque" security origins which do not support storage. - Check storage capabilities on the backend to avoid crasing renderer later. Bug: 850978, 844377 Change-Id: Ib4e2b444473638d896eb716fb7d9c587f5560335 Reviewed-on: https://chromium-review.googlesource.com/1096283 Commit-Queue: Dmitry Gozman Reviewed-by: Alexei Filippov Cr-Original-Commit-Position: refs/heads/master@{#567024} Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src Cr-Mirrored-Commit: 1600a1f6c38cc1e3e56d6ad5b48ca88f01ea8ab2 --- .../resources/ApplicationPanelSidebar.js | 37 ++++++++++++------- front_end/resources/DOMStorageModel.js | 10 ++++- front_end/sdk/TargetManager.js | 3 +- 3 files changed, 34 insertions(+), 16 deletions(-) diff --git a/front_end/resources/ApplicationPanelSidebar.js b/front_end/resources/ApplicationPanelSidebar.js index ae46e2c6bd..4d6b72765b 100644 --- a/front_end/resources/ApplicationPanelSidebar.js +++ b/front_end/resources/ApplicationPanelSidebar.js @@ -29,6 +29,7 @@ */ /** * @implements {SDK.TargetManager.Observer} + * @implements {SDK.SDKModelObserver} * @unrestricted */ Resources.ApplicationPanelSidebar = class extends UI.VBox { @@ -197,14 +198,34 @@ Resources.ApplicationPanelSidebar = class extends UI.VBox { const resourceTreeModel = this._target.model(SDK.ResourceTreeModel); if (resourceTreeModel) this._populateApplicationCacheTree(resourceTreeModel); - const domStorageModel = this._target.model(Resources.DOMStorageModel); - if (domStorageModel) - this._populateDOMStorageTree(domStorageModel); + SDK.targetManager.observeModels(Resources.DOMStorageModel, this); this.indexedDBListTreeElement._initialize(); const serviceWorkerCacheModel = this._target.model(SDK.ServiceWorkerCacheModel); this.cacheStorageListTreeElement._initialize(serviceWorkerCacheModel); } + /** + * @override + * @param {!Resources.DOMStorageModel} domStorageModel + */ + modelAdded(domStorageModel) { + domStorageModel.enable(); + domStorageModel.storages().forEach(this._addDOMStorage.bind(this)); + domStorageModel.addEventListener(Resources.DOMStorageModel.Events.DOMStorageAdded, this._domStorageAdded, this); + domStorageModel.addEventListener(Resources.DOMStorageModel.Events.DOMStorageRemoved, this._domStorageRemoved, this); + } + + /** + * @override + * @param {!Resources.DOMStorageModel} domStorageModel + */ + modelRemoved(domStorageModel) { + domStorageModel.storages().forEach(this._removeDOMStorage.bind(this)); + domStorageModel.removeEventListener(Resources.DOMStorageModel.Events.DOMStorageAdded, this._domStorageAdded, this); + domStorageModel.removeEventListener( + Resources.DOMStorageModel.Events.DOMStorageRemoved, this._domStorageRemoved, this); + } + _resetWithFrames() { this._resourcesSection.reset(); this._reset(); @@ -442,16 +463,6 @@ Resources.ApplicationPanelSidebar = class extends UI.VBox { database.getTableNames(tableNamesCallback); } - /** - * @param {!Resources.DOMStorageModel} domStorageModel - */ - _populateDOMStorageTree(domStorageModel) { - domStorageModel.enable(); - domStorageModel.storages().forEach(this._addDOMStorage.bind(this)); - domStorageModel.addEventListener(Resources.DOMStorageModel.Events.DOMStorageAdded, this._domStorageAdded, this); - domStorageModel.addEventListener(Resources.DOMStorageModel.Events.DOMStorageRemoved, this._domStorageRemoved, this); - } - /** * @param {!SDK.ResourceTreeModel} resourceTreeModel */ diff --git a/front_end/resources/DOMStorageModel.js b/front_end/resources/DOMStorageModel.js index e01000de29..176f1d117b 100644 --- a/front_end/resources/DOMStorageModel.js +++ b/front_end/resources/DOMStorageModel.js @@ -162,6 +162,11 @@ Resources.DOMStorageModel = class extends SDK.SDKModel { * @param {string} securityOrigin */ _addOrigin(securityOrigin) { + const parsed = new Common.ParsedURL(securityOrigin); + // These are "opaque" origins which are not supposed to support DOM storage. + if (!parsed.isValid || parsed.scheme === 'data' || parsed.scheme === 'about' || parsed.scheme === 'javascript') + return; + for (const isLocal of [true, false]) { const key = this._storageKey(securityOrigin, isLocal); console.assert(!this._storages[key]); @@ -185,7 +190,8 @@ Resources.DOMStorageModel = class extends SDK.SDKModel { for (const isLocal of [true, false]) { const key = this._storageKey(securityOrigin, isLocal); const storage = this._storages[key]; - console.assert(storage); + if (!storage) + continue; delete this._storages[key]; this.dispatchEventToListeners(Resources.DOMStorageModel.Events.DOMStorageRemoved, storage); } @@ -273,7 +279,7 @@ Resources.DOMStorageModel = class extends SDK.SDKModel { } }; -SDK.SDKModel.register(Resources.DOMStorageModel, SDK.Target.Capability.None, false); +SDK.SDKModel.register(Resources.DOMStorageModel, SDK.Target.Capability.DOM, false); /** @enum {symbol} */ Resources.DOMStorageModel.Events = { diff --git a/front_end/sdk/TargetManager.js b/front_end/sdk/TargetManager.js index 6c5c0d21bd..268d46f72b 100644 --- a/front_end/sdk/TargetManager.js +++ b/front_end/sdk/TargetManager.js @@ -76,8 +76,9 @@ SDK.TargetManager = class extends Common.Object { * @template T */ observeModels(modelClass, observer) { + const models = this.models(modelClass); this._modelObservers.set(modelClass, observer); - for (const model of this.models(modelClass)) + for (const model of models) observer.modelAdded(model); }