Sat, 03 Jan 2015 20:18:00 +0100
Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.
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
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 "use strict";
7 const Cc = Components.classes;
8 const Ci = Components.interfaces;
9 const Cu = Components.utils;
11 this.EXPORTED_SYMBOLS = ["DownloadsIPC"];
13 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
14 Cu.import("resource://gre/modules/Services.jsm");
15 Cu.import("resource://gre/modules/Promise.jsm");
17 XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
18 "@mozilla.org/childprocessmessagemanager;1",
19 "nsIMessageSender");
21 /**
22 * This module lives in the child process and receives the ipc messages
23 * from the parent. It saves the download's state and redispatch changes
24 * to DOM objects using an observer notification.
25 *
26 * This module needs to be loaded once and only once per process.
27 */
29 function debug(aStr) {
30 #ifdef MOZ_DEBUG
31 dump("-*- DownloadsIPC.jsm : " + aStr + "\n");
32 #endif
33 }
35 const ipcMessages = ["Downloads:Added",
36 "Downloads:Removed",
37 "Downloads:Changed",
38 "Downloads:GetList:Return",
39 "Downloads:ClearAllDone:Return",
40 "Downloads:Remove:Return",
41 "Downloads:Pause:Return",
42 "Downloads:Resume:Return"];
44 this.DownloadsIPC = {
45 downloads: {},
47 init: function() {
48 debug("init");
49 Services.obs.addObserver(this, "xpcom-shutdown", false);
50 ipcMessages.forEach((aMessage) => {
51 cpmm.addMessageListener(aMessage, this);
52 });
54 // We need to get the list of current downloads.
55 this.ready = false;
56 this.getListPromises = [];
57 this.clearAllPromises = [];
58 this.downloadPromises = {};
59 cpmm.sendAsyncMessage("Downloads:GetList", {});
60 this._promiseId = 0;
61 },
63 notifyChanges: function(aId) {
64 // TODO: use the subject instead of stringifying.
65 if (this.downloads[aId]) {
66 debug("notifyChanges notifying changes for " + aId);
67 Services.obs.notifyObservers(null, "downloads-state-change-" + aId,
68 JSON.stringify(this.downloads[aId]));
69 } else {
70 debug("notifyChanges failed for " + aId)
71 }
72 },
74 _updateDownloadsArray: function(aDownloads) {
75 this.downloads = [];
76 // We actually have an array of downloads.
77 aDownloads.forEach((aDownload) => {
78 this.downloads[aDownload.id] = aDownload;
79 });
80 },
82 receiveMessage: function(aMessage) {
83 let download = aMessage.data;
84 debug("message: " + aMessage.name);
85 switch(aMessage.name) {
86 case "Downloads:GetList:Return":
87 this._updateDownloadsArray(download);
89 if (!this.ready) {
90 this.getListPromises.forEach(aPromise =>
91 aPromise.resolve(this.downloads));
92 this.getListPromises.length = 0;
93 }
94 this.ready = true;
95 break;
96 case "Downloads:ClearAllDone:Return":
97 this._updateDownloadsArray(download);
98 this.clearAllPromises.forEach(aPromise =>
99 aPromise.resolve(this.downloads));
100 this.clearAllPromises.length = 0;
101 break;
102 case "Downloads:Added":
103 this.downloads[download.id] = download;
104 this.notifyChanges(download.id);
105 break;
106 case "Downloads:Removed":
107 if (this.downloads[download.id]) {
108 this.downloads[download.id] = download;
109 this.notifyChanges(download.id);
110 delete this.downloads[download.id];
111 }
112 break;
113 case "Downloads:Changed":
114 // Only update properties that actually changed.
115 let cached = this.downloads[download.id];
116 if (!cached) {
117 debug("No download found for " + download.id);
118 return;
119 }
120 let props = ["totalBytes", "currentBytes", "url", "path", "state",
121 "contentType", "startTime"];
122 let changed = false;
124 props.forEach((aProp) => {
125 if (download[aProp] && (download[aProp] != cached[aProp])) {
126 cached[aProp] = download[aProp];
127 changed = true;
128 }
129 });
131 // Updating the error property. We always get a 'state' change as
132 // well.
133 cached.error = download.error;
135 if (changed) {
136 this.notifyChanges(download.id);
137 }
138 break;
139 case "Downloads:Remove:Return":
140 case "Downloads:Pause:Return":
141 case "Downloads:Resume:Return":
142 if (this.downloadPromises[download.promiseId]) {
143 if (!download.error) {
144 this.downloadPromises[download.promiseId].resolve(download);
145 } else {
146 this.downloadPromises[download.promiseId].reject(download);
147 }
148 delete this.downloadPromises[download.promiseId];
149 }
150 break;
151 }
152 },
154 /**
155 * Returns a promise that is resolved with the list of current downloads.
156 */
157 getDownloads: function() {
158 debug("getDownloads()");
159 let deferred = Promise.defer();
160 if (this.ready) {
161 debug("Returning existing list.");
162 deferred.resolve(this.downloads);
163 } else {
164 this.getListPromises.push(deferred);
165 }
166 return deferred.promise;
167 },
169 /**
170 * Returns a promise that is resolved with the list of current downloads.
171 */
172 clearAllDone: function() {
173 debug("clearAllDone");
174 let deferred = Promise.defer();
175 this.clearAllPromises.push(deferred);
176 cpmm.sendAsyncMessage("Downloads:ClearAllDone", {});
177 return deferred.promise;
178 },
180 promiseId: function() {
181 return this._promiseId++;
182 },
184 remove: function(aId) {
185 debug("remove " + aId);
186 let deferred = Promise.defer();
187 let pId = this.promiseId();
188 this.downloadPromises[pId] = deferred;
189 cpmm.sendAsyncMessage("Downloads:Remove",
190 { id: aId, promiseId: pId });
191 return deferred.promise;
192 },
194 pause: function(aId) {
195 debug("pause " + aId);
196 let deferred = Promise.defer();
197 let pId = this.promiseId();
198 this.downloadPromises[pId] = deferred;
199 cpmm.sendAsyncMessage("Downloads:Pause",
200 { id: aId, promiseId: pId });
201 return deferred.promise;
202 },
204 resume: function(aId) {
205 debug("resume " + aId);
206 let deferred = Promise.defer();
207 let pId = this.promiseId();
208 this.downloadPromises[pId] = deferred;
209 cpmm.sendAsyncMessage("Downloads:Resume",
210 { id: aId, promiseId: pId });
211 return deferred.promise;
212 },
214 observe: function(aSubject, aTopic, aData) {
215 if (aTopic == "xpcom-shutdown") {
216 ipcMessages.forEach((aMessage) => {
217 cpmm.removeMessageListener(aMessage, this);
218 });
219 }
220 }
221 };
223 DownloadsIPC.init();