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