Bug 1003860 - Service worker cache for storage actor. r=mratcliffe

This commit is contained in:
Alexandre Poirot 2016-01-25 06:06:48 -08:00
parent d8a7edb911
commit 4eb147fb7a
5 changed files with 145 additions and 0 deletions

View File

@ -54,6 +54,7 @@ tree.labels.cookies=Cookies
tree.labels.localStorage=Local Storage
tree.labels.sessionStorage=Session Storage
tree.labels.indexedDB=Indexed DB
tree.labels.Cache=Cache Storage
# LOCALIZATION NOTE (table.headers.*.*):
# These strings are the header names of the columns in the Storage Table for
@ -84,6 +85,9 @@ table.headers.localStorage.value=Value
table.headers.sessionStorage.name=Key
table.headers.sessionStorage.value=Value
table.headers.Cache.url=URL
table.headers.Cache.status=Status
table.headers.indexedDB.name=Key
table.headers.indexedDB.db=Database Name
table.headers.indexedDB.objectStore=Object Store Name

View File

@ -61,6 +61,9 @@ const testCases = [
[6, 7]],
[["indexedDB", "https://sectest1.example.org", "idb-s2", "obj-s2"],
[16]],
[["Cache", "http://test1.example.org", "plop"],
[MAIN_DOMAIN + "404_cached_file.js", MAIN_DOMAIN + "browser_storage_basic.js"]],
];
/**

View File

@ -14,6 +14,8 @@ const SPLIT_CONSOLE_PREF = "devtools.toolbox.splitconsoleEnabled";
const STORAGE_PREF = "devtools.storage.enabled";
const DUMPEMIT_PREF = "devtools.dump.emit";
const DEBUGGERLOG_PREF = "devtools.debugger.log";
// Allows Cache API to be working on usage `http` test page
const CACHES_ON_HTTP_PREF = "dom.caches.testing.enabled";
const PATH = "browser/devtools/client/storage/test/";
const MAIN_DOMAIN = "http://test1.example.org/" + PATH;
const ALT_DOMAIN = "http://sectest1.example.org/" + PATH;
@ -27,6 +29,7 @@ var gToolbox, gPanelWindow, gWindow, gUI;
// Services.prefs.setBoolPref(DEBUGGERLOG_PREF, true);
Services.prefs.setBoolPref(STORAGE_PREF, true);
Services.prefs.setBoolPref(CACHES_ON_HTTP_PREF, true);
DevToolsUtils.testing = true;
registerCleanupFunction(() => {
gToolbox = gPanelWindow = gWindow = gUI = null;
@ -34,6 +37,7 @@ registerCleanupFunction(() => {
Services.prefs.clearUserPref(SPLIT_CONSOLE_PREF);
Services.prefs.clearUserPref(DUMPEMIT_PREF);
Services.prefs.clearUserPref(DEBUGGERLOG_PREF);
Services.prefs.clearUserPref(CACHES_ON_HTTP_PREF);
DevToolsUtils.testing = false;
while (gBrowser.tabs.length > 1) {
gBrowser.removeCurrentTab();

View File

@ -97,8 +97,15 @@ function deleteDB(dbName) {
});
}
let cacheGenerator = function*() {
let cache = yield caches.open("plop");
yield cache.add("404_cached_file.js");
yield cache.add("browser_storage_basic.js");
};
window.setup = function*() {
yield idbGenerator();
yield cacheGenerator();
};
window.clear = function*() {
@ -115,6 +122,8 @@ window.clear = function*() {
yield deleteDB("idb1");
yield deleteDB("idb2");
yield caches.delete("plop");
dump("removed cookies, localStorage, sessionStorage and indexedDB data " +
"from " + document.location + "\n");
};

View File

@ -922,6 +922,131 @@ StorageActors.createActor({
storeObjectType: "storagestoreobject"
}, getObjectForLocalOrSessionStorage("sessionStorage"));
let CacheAttributes = [
"url",
"status",
];
types.addDictType("cacheobject", {
"url": "string",
"status": "string"
});
// Array of Cache store objects
types.addDictType("cachestoreobject", {
total: "number",
offset: "number",
data: "array:nullable:cacheobject"
});
StorageActors.createActor({
typeName: "Cache",
storeObjectType: "cachestoreobject"
}, {
getCachesForHost: Task.async(function*(host) {
let uri = Services.io.newURI(host, null, null);
let principal = Services.scriptSecurityManager.getNoAppCodebasePrincipal(uri);
// The first argument tells if you want to get |content| cache or |chrome| cache.
// The |content| cache is the cache explicitely named by the web content
// (service worker or web page).
// The |chrome| cache is the cache implicitely cached by the platform, hosting the
// source file of the service worker.
let { CacheStorage } = this.storageActor.window;
let cache = new CacheStorage("content", principal);
return cache;
}),
preListStores: Task.async(function*() {
for (let host of this.hosts) {
yield this.populateStoresForHost(host);
}
}),
form: function(form, detail) {
if (detail === "actorid") {
return this.actorID;
}
let hosts = {};
for (let host of this.hosts) {
hosts[host] = this.getNamesForHost(host);
}
return {
actor: this.actorID,
hosts: hosts
};
},
getNamesForHost: function(host) {
// UI code expect each name to be a JSON string of an array :/
return [...this.hostVsStores.get(host).keys()].map(a => JSON.stringify([a]));
},
getValuesForHost: Task.async(function*(host, name) {
if (!name) return [];
// UI is weird and expect a JSON stringified array... and pass it back :/
name = JSON.parse(name)[0];
let cache = this.hostVsStores.get(host).get(name);
let requests = yield cache.keys();
let results = [];
for(let request of requests) {
let response = yield cache.match(request);
// Unwrap the response to get access to all its properties if the
// response happen to be 'opaque', when it is a Cross Origin Request.
response = response.cloneUnfiltered();
results.push(yield this.processEntry(request, response));
}
return results;
}),
processEntry: Task.async(function*(request, response) {
return {
url: String(request.url),
status: String(response.statusText),
};
}),
getHostName: function(location) {
if (!location.host) {
return location.href;
}
return location.protocol + "//" + location.host;
},
populateStoresForHost: Task.async(function*(host, window) {
let storeMap = new Map();
let caches = yield this.getCachesForHost(host);
for (let name of (yield caches.keys())) {
storeMap.set(name, (yield caches.open(name)));
}
this.hostVsStores.set(host, storeMap);
}),
/**
* This method is overriden and left blank as for Cache Storage, this
* operation cannot be performed synchronously. Thus, the preListStores
* method exists to do the same task asynchronously.
*/
populateStoresForHosts: function() {
this.hostVsStores = new Map();
},
/**
* Given a url, correctly determine its protocol + hostname part.
*/
getSchemaAndHost: function(url) {
let uri = Services.io.newURI(url, null, null);
return uri.scheme + "://" + uri.hostPort;
},
toStoreObject: function(item) {
return item;
},
});
/**
* Code related to the Indexed DB actor and front
*/