blob: 519280d50f418e90ea2bcea6c821ee4d05c351c6 [file] [log] [blame]
/*
* Copyright (C) 2008 Nokia Inc. All rights reserved.
* Copyright (C) 2013 Samsung Electronics. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @unrestricted
*/
Resources.DOMStorage = class extends Common.Object {
/**
* @param {!Resources.DOMStorageModel} model
* @param {string} securityOrigin
* @param {boolean} isLocalStorage
*/
constructor(model, securityOrigin, isLocalStorage) {
super();
this._model = model;
this._securityOrigin = securityOrigin;
this._isLocalStorage = isLocalStorage;
}
/**
* @param {string} securityOrigin
* @param {boolean} isLocalStorage
* @return {!Protocol.DOMStorage.StorageId}
*/
static storageId(securityOrigin, isLocalStorage) {
return {securityOrigin: securityOrigin, isLocalStorage: isLocalStorage};
}
/** @return {!Protocol.DOMStorage.StorageId} */
get id() {
return Resources.DOMStorage.storageId(this._securityOrigin, this._isLocalStorage);
}
/** @return {string} */
get securityOrigin() {
return this._securityOrigin;
}
/** @return {boolean} */
get isLocalStorage() {
return this._isLocalStorage;
}
/**
* @return {!Promise<?Array<!Protocol.DOMStorage.Item>>}
*/
getItems() {
return this._model._agent.getDOMStorageItems(this.id);
}
/**
* @param {string} key
* @param {string} value
*/
setItem(key, value) {
this._model._agent.setDOMStorageItem(this.id, key, value);
}
/**
* @param {string} key
*/
removeItem(key) {
this._model._agent.removeDOMStorageItem(this.id, key);
}
clear() {
this._model._agent.clear(this.id);
}
};
/** @enum {symbol} */
Resources.DOMStorage.Events = {
DOMStorageItemsCleared: Symbol('DOMStorageItemsCleared'),
DOMStorageItemRemoved: Symbol('DOMStorageItemRemoved'),
DOMStorageItemAdded: Symbol('DOMStorageItemAdded'),
DOMStorageItemUpdated: Symbol('DOMStorageItemUpdated')
};
/**
* @unrestricted
*/
Resources.DOMStorageModel = class extends SDK.SDKModel {
/**
* @param {!SDK.Target} target
*/
constructor(target) {
super(target);
this._securityOriginManager = target.model(SDK.SecurityOriginManager);
/** @type {!Object.<string, !Resources.DOMStorage>} */
this._storages = {};
this._agent = target.domstorageAgent();
}
enable() {
if (this._enabled) {
return;
}
this.target().registerDOMStorageDispatcher(new Resources.DOMStorageDispatcher(this));
this._securityOriginManager.addEventListener(
SDK.SecurityOriginManager.Events.SecurityOriginAdded, this._securityOriginAdded, this);
this._securityOriginManager.addEventListener(
SDK.SecurityOriginManager.Events.SecurityOriginRemoved, this._securityOriginRemoved, this);
for (const securityOrigin of this._securityOriginManager.securityOrigins()) {
this._addOrigin(securityOrigin);
}
this._agent.enable();
this._enabled = true;
}
/**
* @param {string} origin
*/
clearForOrigin(origin) {
if (!this._enabled) {
return;
}
for (const isLocal of [true, false]) {
const key = this._storageKey(origin, isLocal);
const storage = this._storages[key];
storage.clear();
}
this._removeOrigin(origin);
this._addOrigin(origin);
}
/**
* @param {!Common.Event} event
*/
_securityOriginAdded(event) {
this._addOrigin(/** @type {string} */ (event.data));
}
/**
* @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]);
const storage = new Resources.DOMStorage(this, securityOrigin, isLocal);
this._storages[key] = storage;
this.dispatchEventToListeners(Resources.DOMStorageModel.Events.DOMStorageAdded, storage);
}
}
/**
* @param {!Common.Event} event
*/
_securityOriginRemoved(event) {
this._removeOrigin(/** @type {string} */ (event.data));
}
/**
* @param {string} securityOrigin
*/
_removeOrigin(securityOrigin) {
for (const isLocal of [true, false]) {
const key = this._storageKey(securityOrigin, isLocal);
const storage = this._storages[key];
if (!storage) {
continue;
}
delete this._storages[key];
this.dispatchEventToListeners(Resources.DOMStorageModel.Events.DOMStorageRemoved, storage);
}
}
/**
* @param {string} securityOrigin
* @param {boolean} isLocalStorage
* @return {string}
*/
_storageKey(securityOrigin, isLocalStorage) {
return JSON.stringify(Resources.DOMStorage.storageId(securityOrigin, isLocalStorage));
}
/**
* @param {!Protocol.DOMStorage.StorageId} storageId
*/
_domStorageItemsCleared(storageId) {
const domStorage = this.storageForId(storageId);
if (!domStorage) {
return;
}
const eventData = {};
domStorage.dispatchEventToListeners(Resources.DOMStorage.Events.DOMStorageItemsCleared, eventData);
}
/**
* @param {!Protocol.DOMStorage.StorageId} storageId
* @param {string} key
*/
_domStorageItemRemoved(storageId, key) {
const domStorage = this.storageForId(storageId);
if (!domStorage) {
return;
}
const eventData = {key: key};
domStorage.dispatchEventToListeners(Resources.DOMStorage.Events.DOMStorageItemRemoved, eventData);
}
/**
* @param {!Protocol.DOMStorage.StorageId} storageId
* @param {string} key
* @param {string} value
*/
_domStorageItemAdded(storageId, key, value) {
const domStorage = this.storageForId(storageId);
if (!domStorage) {
return;
}
const eventData = {key: key, value: value};
domStorage.dispatchEventToListeners(Resources.DOMStorage.Events.DOMStorageItemAdded, eventData);
}
/**
* @param {!Protocol.DOMStorage.StorageId} storageId
* @param {string} key
* @param {string} oldValue
* @param {string} value
*/
_domStorageItemUpdated(storageId, key, oldValue, value) {
const domStorage = this.storageForId(storageId);
if (!domStorage) {
return;
}
const eventData = {key: key, oldValue: oldValue, value: value};
domStorage.dispatchEventToListeners(Resources.DOMStorage.Events.DOMStorageItemUpdated, eventData);
}
/**
* @param {!Protocol.DOMStorage.StorageId} storageId
* @return {!Resources.DOMStorage}
*/
storageForId(storageId) {
return this._storages[JSON.stringify(storageId)];
}
/**
* @return {!Array.<!Resources.DOMStorage>}
*/
storages() {
const result = [];
for (const id in this._storages) {
result.push(this._storages[id]);
}
return result;
}
};
SDK.SDKModel.register(Resources.DOMStorageModel, SDK.Target.Capability.DOM, false);
/** @enum {symbol} */
Resources.DOMStorageModel.Events = {
DOMStorageAdded: Symbol('DOMStorageAdded'),
DOMStorageRemoved: Symbol('DOMStorageRemoved')
};
/**
* @implements {Protocol.DOMStorageDispatcher}
* @unrestricted
*/
Resources.DOMStorageDispatcher = class {
/**
* @param {!Resources.DOMStorageModel} model
*/
constructor(model) {
this._model = model;
}
/**
* @override
* @param {!Protocol.DOMStorage.StorageId} storageId
*/
domStorageItemsCleared(storageId) {
this._model._domStorageItemsCleared(storageId);
}
/**
* @override
* @param {!Protocol.DOMStorage.StorageId} storageId
* @param {string} key
*/
domStorageItemRemoved(storageId, key) {
this._model._domStorageItemRemoved(storageId, key);
}
/**
* @override
* @param {!Protocol.DOMStorage.StorageId} storageId
* @param {string} key
* @param {string} value
*/
domStorageItemAdded(storageId, key, value) {
this._model._domStorageItemAdded(storageId, key, value);
}
/**
* @override
* @param {!Protocol.DOMStorage.StorageId} storageId
* @param {string} key
* @param {string} oldValue
* @param {string} value
*/
domStorageItemUpdated(storageId, key, oldValue, value) {
this._model._domStorageItemUpdated(storageId, key, oldValue, value);
}
};