diff --git a/browser/components/sessionstore/src/nsSessionStore.js b/browser/components/sessionstore/src/nsSessionStore.js index a79aafb23ed5..40b9b54cb939 100644 --- a/browser/components/sessionstore/src/nsSessionStore.js +++ b/browser/components/sessionstore/src/nsSessionStore.js @@ -550,6 +550,7 @@ SessionStoreService.prototype = { delete aTab.linkedBrowser.__SS_data; delete aTab.linkedBrowser.__SS_tabStillLoading; delete aTab.linkedBrowser.__SS_formDataSaved; + delete aTab.linkedBrowser.__SS_hostSchemeData; if (aTab.linkedBrowser.__SS_restoreState) this._resetTabRestoringState(aTab); }); @@ -1058,6 +1059,7 @@ SessionStoreService.prototype = { delete browser.__SS_data; delete browser.__SS_tabStillLoading; delete browser.__SS_formDataSaved; + delete browser.__SS_hostSchemeData; // If this tab was in the middle of restoring or still needs to be restored, // we need to reset that state. If the tab was restoring, we will attempt to @@ -1757,10 +1759,11 @@ SessionStoreService.prototype = { tabData.index = history.index + 1; } else if (history && history.count > 0) { + browser.__SS_hostSchemeData = []; try { for (var j = 0; j < history.count; j++) { let entry = this._serializeHistoryEntry(history.getEntryAtIndex(j, false), - aFullData, aTab.pinned); + aFullData, aTab.pinned, browser.__SS_hostSchemeData); tabData.entries.push(entry); } // If we make it through the for loop, then we're ok and we should clear @@ -1849,15 +1852,16 @@ SessionStoreService.prototype = { * always return privacy sensitive data (use with care) * @param aIsPinned * the tab is pinned and should be treated differently for privacy + * @param aHostSchemeData + * an array of objects with host & scheme keys * @returns object */ _serializeHistoryEntry: - function sss_serializeHistoryEntry(aEntry, aFullData, aIsPinned) { + function sss_serializeHistoryEntry(aEntry, aFullData, aIsPinned, aHostSchemeData) { var entry = { url: aEntry.URI.spec }; try { - entry._host = aEntry.URI.host; - entry._scheme = aEntry.URI.scheme; + aHostSchemeData.push({ host: aEntry.URI.host, scheme: aEntry.URI.scheme }); } catch (ex) { // We just won't attempt to get cookies for this entry. @@ -1960,7 +1964,7 @@ SessionStoreService.prototype = { var child = aEntry.GetChildAt(i); if (child) { entry.children.push(this._serializeHistoryEntry(child, aFullData, - aIsPinned)); + aIsPinned, aHostSchemeData)); } else { // to maintain the correct frame order, insert a dummy entry entry.children.push({ url: "about:blank" }); @@ -2274,8 +2278,8 @@ SessionStoreService.prototype = { * is the entry we're evaluating for a pinned tab; used only if * aCheckPrivacy */ - _extractHostsForCookies: - function sss__extractHostsForCookies(aEntry, aHosts, aCheckPrivacy, aIsPinned) { + _extractHostsForCookiesFromEntry: + function sss__extractHostsForCookiesFromEntry(aEntry, aHosts, aCheckPrivacy, aIsPinned) { let host = aEntry._host, scheme = aEntry._scheme; @@ -2289,23 +2293,11 @@ SessionStoreService.prototype = { let uri = this._getURIFromString(aEntry.url); host = uri.host; scheme = uri.scheme; + this._extractHostsForCookiesFromHostScheme(host, scheme, aHosts, aCheckPrivacy, aIsPinned); } catch(ex) { } } - // host and scheme may not be set (for about: urls for example), in which - // case testing scheme will be sufficient. - if (/https?/.test(scheme) && !aHosts[host] && - (!aCheckPrivacy || - this._checkPrivacyLevel(scheme == "https", aIsPinned))) { - // By setting this to true or false, we can determine when looking at - // the host in _updateCookies if we should check for privacy. - aHosts[host] = aIsPinned; - } - else if (scheme == "file") { - aHosts[host] = true; - } - if (aEntry.children) { aEntry.children.forEach(function(entry) { this._extractHostsForCookies(entry, aHosts, aCheckPrivacy, aIsPinned); @@ -2313,6 +2305,36 @@ SessionStoreService.prototype = { } }, + /** + * extract the base domain from a host & scheme + * @param aHost + * the host of a uri (usually via nsIURI.host) + * @param aScheme + * the scheme of a uri (usually via nsIURI.scheme) + * @param aHosts + * the hash that will be used to store hosts eg, { hostname: true } + * @param aCheckPrivacy + * should we check the privacy level for https + * @param aIsPinned + * is the entry we're evaluating for a pinned tab; used only if + * aCheckPrivacy + */ + _extractHostsForCookiesFromHostScheme: + function sss__extractHostsForCookiesFromHostScheme(aHost, aScheme, aHosts, aCheckPrivacy, aIsPinned) { + // host and scheme may not be set (for about: urls for example), in which + // case testing scheme will be sufficient. + if (/https?/.test(aScheme) && !aHosts[aHost] && + (!aCheckPrivacy || + this._checkPrivacyLevel(aScheme == "https", aIsPinned))) { + // By setting this to true or false, we can determine when looking at + // the host in _updateCookies if we should check for privacy. + aHosts[aHost] = aIsPinned; + } + else if (aScheme == "file") { + aHosts[aHost] = true; + } + }, + /** * store all hosts for a URL * @param aWindow @@ -2321,11 +2343,18 @@ SessionStoreService.prototype = { _updateCookieHosts: function sss_updateCookieHosts(aWindow) { var hosts = this._internalWindows[aWindow.__SSi].hosts = {}; - this._windows[aWindow.__SSi].tabs.forEach(function(aTabData) { - aTabData.entries.forEach(function(entry) { - this._extractHostsForCookies(entry, hosts, true, !!aTabData.pinned); - }, this); - }, this); + // Since _updateCookiesHosts is only ever called for open windows during a + // session, we can call into _extractHostsForCookiesFromHostScheme directly + // using data that is attached to each browser. + for (let i = 0; i < aWindow.gBrowser.tabs.length; i++) { + let tab = aWindow.gBrowser.tabs[i]; + let hostSchemeData = tab.linkedBrowser.__SS_hostSchemeData || []; + for (let j = 0; j < hostSchemeData.length; j++) { + this._extractHostsForCookiesFromHostScheme(hostSchemeData[j].host, + hostSchemeData[j].scheme, + hosts, true, tab.pinned); + } + } }, /** @@ -4069,7 +4098,7 @@ SessionStoreService.prototype = { let cookieHosts = {}; aTargetWinState.tabs.forEach(function(tab) { tab.entries.forEach(function(entry) { - this._extractHostsForCookies(entry, cookieHosts, false) + this._extractHostsForCookiesFromEntry(entry, cookieHosts, false); }, this); }, this);