browser/components/sessionstore/src/SessionStorage.jsm

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
michael@0 3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 "use strict";
michael@0 6
michael@0 7 this.EXPORTED_SYMBOLS = ["SessionStorage"];
michael@0 8
michael@0 9 const Cu = Components.utils;
michael@0 10 const Ci = Components.interfaces;
michael@0 11
michael@0 12 Cu.import("resource://gre/modules/Services.jsm");
michael@0 13 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
michael@0 14
michael@0 15 XPCOMUtils.defineLazyModuleGetter(this, "console",
michael@0 16 "resource://gre/modules/devtools/Console.jsm");
michael@0 17
michael@0 18 // Returns the principal for a given |frame| contained in a given |docShell|.
michael@0 19 function getPrincipalForFrame(docShell, frame) {
michael@0 20 let ssm = Services.scriptSecurityManager;
michael@0 21 let uri = frame.document.documentURIObject;
michael@0 22 return ssm.getDocShellCodebasePrincipal(uri, docShell);
michael@0 23 }
michael@0 24
michael@0 25 this.SessionStorage = Object.freeze({
michael@0 26 /**
michael@0 27 * Updates all sessionStorage "super cookies"
michael@0 28 * @param docShell
michael@0 29 * That tab's docshell (containing the sessionStorage)
michael@0 30 * @param frameTree
michael@0 31 * The docShell's FrameTree instance.
michael@0 32 * @return Returns a nested object that will have hosts as keys and per-host
michael@0 33 * session storage data as values. For example:
michael@0 34 * {"example.com": {"key": "value", "my_number": 123}}
michael@0 35 */
michael@0 36 collect: function (docShell, frameTree) {
michael@0 37 return SessionStorageInternal.collect(docShell, frameTree);
michael@0 38 },
michael@0 39
michael@0 40 /**
michael@0 41 * Restores all sessionStorage "super cookies".
michael@0 42 * @param aDocShell
michael@0 43 * A tab's docshell (containing the sessionStorage)
michael@0 44 * @param aStorageData
michael@0 45 * A nested object with storage data to be restored that has hosts as
michael@0 46 * keys and per-host session storage data as values. For example:
michael@0 47 * {"example.com": {"key": "value", "my_number": 123}}
michael@0 48 */
michael@0 49 restore: function (aDocShell, aStorageData) {
michael@0 50 SessionStorageInternal.restore(aDocShell, aStorageData);
michael@0 51 }
michael@0 52 });
michael@0 53
michael@0 54 let SessionStorageInternal = {
michael@0 55 /**
michael@0 56 * Reads all session storage data from the given docShell.
michael@0 57 * @param docShell
michael@0 58 * A tab's docshell (containing the sessionStorage)
michael@0 59 * @param frameTree
michael@0 60 * The docShell's FrameTree instance.
michael@0 61 * @return Returns a nested object that will have hosts as keys and per-host
michael@0 62 * session storage data as values. For example:
michael@0 63 * {"example.com": {"key": "value", "my_number": 123}}
michael@0 64 */
michael@0 65 collect: function (docShell, frameTree) {
michael@0 66 let data = {};
michael@0 67 let visitedOrigins = new Set();
michael@0 68
michael@0 69 frameTree.forEach(frame => {
michael@0 70 let principal = getPrincipalForFrame(docShell, frame);
michael@0 71 if (!principal) {
michael@0 72 return;
michael@0 73 }
michael@0 74
michael@0 75 // Get the root domain of the current history entry
michael@0 76 // and use that as a key for the per-host storage data.
michael@0 77 let origin = principal.jarPrefix + principal.origin;
michael@0 78 if (visitedOrigins.has(origin)) {
michael@0 79 // Don't read a host twice.
michael@0 80 return;
michael@0 81 }
michael@0 82
michael@0 83 // Mark the current origin as visited.
michael@0 84 visitedOrigins.add(origin);
michael@0 85
michael@0 86 let originData = this._readEntry(principal, docShell);
michael@0 87 if (Object.keys(originData).length) {
michael@0 88 data[origin] = originData;
michael@0 89 }
michael@0 90 });
michael@0 91
michael@0 92 return Object.keys(data).length ? data : null;
michael@0 93 },
michael@0 94
michael@0 95 /**
michael@0 96 * Writes session storage data to the given tab.
michael@0 97 * @param aDocShell
michael@0 98 * A tab's docshell (containing the sessionStorage)
michael@0 99 * @param aStorageData
michael@0 100 * A nested object with storage data to be restored that has hosts as
michael@0 101 * keys and per-host session storage data as values. For example:
michael@0 102 * {"example.com": {"key": "value", "my_number": 123}}
michael@0 103 */
michael@0 104 restore: function (aDocShell, aStorageData) {
michael@0 105 for (let host of Object.keys(aStorageData)) {
michael@0 106 let data = aStorageData[host];
michael@0 107 let uri = Services.io.newURI(host, null, null);
michael@0 108 let principal = Services.scriptSecurityManager.getDocShellCodebasePrincipal(uri, aDocShell);
michael@0 109 let storageManager = aDocShell.QueryInterface(Ci.nsIDOMStorageManager);
michael@0 110
michael@0 111 // There is no need to pass documentURI, it's only used to fill documentURI property of
michael@0 112 // domstorage event, which in this case has no consumer. Prevention of events in case
michael@0 113 // of missing documentURI will be solved in a followup bug to bug 600307.
michael@0 114 // TODO: We should call createStorageForFirstParty() here. See comment
michael@0 115 // inside _readEntry() for details.
michael@0 116 let storage = storageManager.createStorage(principal, "", aDocShell.usePrivateBrowsing);
michael@0 117
michael@0 118 for (let key of Object.keys(data)) {
michael@0 119 try {
michael@0 120 storage.setItem(key, data[key]);
michael@0 121 } catch (e) {
michael@0 122 // throws e.g. for URIs that can't have sessionStorage
michael@0 123 console.error(e);
michael@0 124 }
michael@0 125 }
michael@0 126 }
michael@0 127 },
michael@0 128
michael@0 129 /**
michael@0 130 * Reads an entry in the session storage data contained in a tab's history.
michael@0 131 * @param aURI
michael@0 132 * That history entry uri
michael@0 133 * @param aDocShell
michael@0 134 * A tab's docshell (containing the sessionStorage)
michael@0 135 */
michael@0 136 _readEntry: function (aPrincipal, aDocShell) {
michael@0 137 let hostData = {};
michael@0 138 let storage;
michael@0 139
michael@0 140 try {
michael@0 141 let storageManager = aDocShell.QueryInterface(Ci.nsIDOMStorageManager);
michael@0 142 // TODO: We should call getStorageForFirstParty() here, but we need an
michael@0 143 // nsIDocument to call thirdPartyUtil.getFirstPartyURI(), and
michael@0 144 // unfortunately nsIDocument is not exposed to JavaScript.
michael@0 145 // However, this code is not called in TBB because the
michael@0 146 // browser.sessionstore.privacy_level pref. is set to 2.
michael@0 147 storage = storageManager.getStorage(aPrincipal);
michael@0 148 } catch (e) {
michael@0 149 // sessionStorage might throw if it's turned off, see bug 458954
michael@0 150 }
michael@0 151
michael@0 152 if (storage && storage.length) {
michael@0 153 for (let i = 0; i < storage.length; i++) {
michael@0 154 try {
michael@0 155 let key = storage.key(i);
michael@0 156 hostData[key] = storage.getItem(key);
michael@0 157 } catch (e) {
michael@0 158 // This currently throws for secured items (cf. bug 442048).
michael@0 159 }
michael@0 160 }
michael@0 161 }
michael@0 162
michael@0 163 return hostData;
michael@0 164 }
michael@0 165 };

mercurial