Bug 742047 - Part 2 - Refactor SessionStorage.jsm and its API; r=zpao

This commit is contained in:
Tim Taubert 2012-06-03 11:45:51 +02:00
parent 4265aa8a1a
commit 088d9c2a9e
2 changed files with 147 additions and 82 deletions

View File

@ -15,95 +15,158 @@ XPCOMUtils.defineLazyModuleGetter(this, "SessionStore",
let SessionStorage = {
/**
* Updates all sessionStorage "super cookies"
* @param aTabData
* The data object for a specific tab
* @param aHistory
* That tab's session history
* @param aDocShell
* That tab's docshell (containing the sessionStorage)
* @param aFullData
* always return privacy sensitive data (use with care)
* @param aIsPinned
* the tab is pinned and should be treated differently for privacy
*/
serialize: function ssto_serialize(aTabData, aHistory, aDocShell, aFullData,
aIsPinned) {
let storageData = {};
let hasContent = false;
for (let i = 0; i < aHistory.count; i++) {
let uri;
try {
uri = aHistory.getEntryAtIndex(i, false).URI;
}
catch (ex) {
// Chances are that this is getEntryAtIndex throwing, as seen in bug 669196.
// We've already asserted in _collectTabData, so we won't show that again.
continue;
}
// sessionStorage is saved per origin (cf. nsDocShell::GetSessionStorageForURI)
let domain = uri.spec;
try {
if (uri.host)
domain = uri.prePath;
}
catch (ex) { /* this throws for host-less URIs (such as about: or jar:) */ }
if (storageData[domain] ||
!(aFullData || SessionStore.checkPrivacyLevel(uri.schemeIs("https"), aIsPinned)))
continue;
let storage, storageItemCount = 0;
try {
var principal = Services.scriptSecurityManager.getCodebasePrincipal(uri);
// Using getSessionStorageForPrincipal instead of getSessionStorageForURI
// just to be able to pass aCreate = false, that avoids creation of the
// sessionStorage object for the page earlier than the page really
// requires it. It was causing problems while accessing a storage when
// a page later changed its domain.
storage = aDocShell.getSessionStorageForPrincipal(principal, "", false);
if (storage)
storageItemCount = storage.length;
}
catch (ex) { /* sessionStorage might throw if it's turned off, see bug 458954 */ }
if (storageItemCount == 0)
continue;
let data = storageData[domain] = {};
for (let j = 0; j < storageItemCount; j++) {
try {
let key = storage.key(j);
let item = storage.getItem(key);
data[key] = item;
}
catch (ex) { /* this currently throws for secured items (cf. bug 442048) */ }
}
hasContent = true;
}
if (hasContent)
aTabData.storage = storageData;
serialize: function ssto_serialize(aDocShell, aFullData) {
return DomStorage.read(aDocShell, aFullData);
},
/**
* restores all sessionStorage "super cookies"
* @param aStorageData
* Storage data to be restored
* Restores all sessionStorage "super cookies".
* @param aDocShell
* A tab's docshell (containing the sessionStorage)
* @param aStorageData
* Storage data to be restored
*/
deserialize: function ssto_deserialize(aStorageData, aDocShell) {
for (let url in aStorageData) {
let uri = Services.io.newURI(url, null, null);
let storage = aDocShell.getSessionStorageForURI(uri, "");
for (let key in aStorageData[url]) {
try {
storage.setItem(key, aStorageData[url][key]);
}
catch (ex) { Cu.reportError(ex); } // throws e.g. for URIs that can't have sessionStorage
}
}
deserialize: function ssto_deserialize(aDocShell, aStorageData) {
DomStorage.write(aDocShell, aStorageData);
}
};
Object.freeze(SessionStorage);
let DomStorage = {
/**
* Reads all session storage data from the given docShell.
* @param aDocShell
* A tab's docshell (containing the sessionStorage)
* @param aFullData
* Always return privacy sensitive data (use with care)
*/
read: function DomStorage_read(aDocShell, aFullData) {
let data = {};
let isPinned = aDocShell.isAppTab;
let shistory = aDocShell.sessionHistory;
for (let i = 0; i < shistory.count; i++) {
let uri = History.getUriForEntry(shistory, i);
if (uri) {
// Check if we're allowed to store sessionStorage data.
let isHTTPS = uri.schemeIs("https");
if (aFullData || SessionStore.checkPrivacyLevel(isHTTPS, isPinned)) {
let host = History.getHostForURI(uri);
// Don't read a host twice.
if (!(host in data)) {
let hostData = this._readEntry(uri, aDocShell);
if (Object.keys(hostData).length) {
data[host] = hostData;
}
}
}
}
}
return data;
},
/**
* Writes session storage data to the given tab.
* @param aDocShell
* A tab's docshell (containing the sessionStorage)
* @param aStorageData
* Storage data to be restored
*/
write: function DomStorage_write(aDocShell, aStorageData) {
for (let [host, data] in Iterator(aStorageData)) {
let uri = Services.io.newURI(host, null, null);
let storage = aDocShell.getSessionStorageForURI(uri, "");
for (let [key, value] in Iterator(data)) {
try {
storage.setItem(key, value);
} catch (e) {
// throws e.g. for URIs that can't have sessionStorage
Cu.reportError(e);
}
}
}
},
/**
* Reads an entry in the session storage data contained in a tab's history.
* @param aURI
* That history entry uri
* @param aDocShell
* A tab's docshell (containing the sessionStorage)
*/
_readEntry: function DomStorage_readEntry(aURI, aDocShell) {
let hostData = {};
let storage;
try {
let principal = Services.scriptSecurityManager.getCodebasePrincipal(aURI);
// Using getSessionStorageForPrincipal instead of
// getSessionStorageForURI just to be able to pass aCreate = false,
// that avoids creation of the sessionStorage object for the page
// earlier than the page really requires it. It was causing problems
// while accessing a storage when a page later changed its domain.
storage = aDocShell.getSessionStorageForPrincipal(principal, "", false);
} catch (e) {
// sessionStorage might throw if it's turned off, see bug 458954
}
if (storage && storage.length) {
for (let i = 0; i < storage.length; i++) {
try {
let key = storage.key(i);
hostData[key] = storage.getItem(key);
} catch (e) {
// This currently throws for secured items (cf. bug 442048).
}
}
}
return hostData;
}
};
let History = {
/**
* Returns a given history entry's URI.
* @param aHistory
* That tab's session history
* @param aIndex
* The history entry's index
*/
getUriForEntry: function History_getUriForEntry(aHistory, aIndex) {
try {
return aHistory.getEntryAtIndex(aIndex, false).URI;
} catch (e) {
// This might throw for some reason.
}
},
/**
* Returns the host of a given URI.
* @param aURI
* The URI for which to return the host
*/
getHostForURI: function History_getHostForURI(aURI) {
let host = aURI.spec;
try {
if (aURI.host)
host = aURI.prePath;
} catch (e) {
// This throws for host-less URIs (such as about: or jar:).
}
return host;
}
};

View File

@ -87,7 +87,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "ScratchpadManager",
XPCOMUtils.defineLazyModuleGetter(this, "DocumentUtils",
"resource:///modules/sessionstore/DocumentUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "SessionStorage",
"resource:///modules/sessionstore/SessionStorage.jsm");
"resource:///modules/sessionstore/SessionStorage.jsm");
#ifdef MOZ_CRASHREPORTER
XPCOMUtils.defineLazyServiceGetter(this, "CrashReporter",
@ -1993,9 +1993,11 @@ let SessionStoreInternal = {
else if (tabData.extData)
delete tabData.extData;
if (history && browser.docShell instanceof Ci.nsIDocShell)
SessionStorage.serialize(tabData, history, browser.docShell, aFullData,
aTab.pinned);
if (history && browser.docShell instanceof Ci.nsIDocShell) {
let storageData = SessionStorage.serialize(browser.docShell, aFullData)
if (Object.keys(storageData).length)
tabData.storage = storageData;
}
return tabData;
},
@ -3061,7 +3063,7 @@ let SessionStoreInternal = {
tab.setAttribute(name, tabData.attributes[name]);
if (tabData.storage && browser.docShell instanceof Ci.nsIDocShell)
SessionStorage.deserialize(tabData.storage, browser.docShell);
SessionStorage.deserialize(browser.docShell, tabData.storage);
// notify the tabbrowser that the tab chrome has been restored
var event = aWindow.document.createEvent("Events");