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 = [];
13 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
14 Cu.import("resource://gre/modules/Downloads.jsm");
15 Cu.import("resource://gre/modules/Task.jsm");
17 XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
18 "@mozilla.org/parentprocessmessagemanager;1",
19 "nsIMessageBroadcaster");
21 function debug(aStr) {
22 #ifdef MOZ_DEBUG
23 dump("-*- DownloadsAPI.jsm : " + aStr + "\n");
24 #endif
25 }
27 function sendPromiseMessage(aMm, aMessageName, aData, aError) {
28 debug("sendPromiseMessage " + aMessageName);
29 let msg = {
30 id: aData.id,
31 promiseId: aData.promiseId
32 };
34 if (aError) {
35 msg.error = aError;
36 }
38 aMm.sendAsyncMessage(aMessageName, msg);
39 }
41 let DownloadsAPI = {
42 init: function() {
43 debug("init");
45 this._ids = new WeakMap(); // Maps toolkit download objects to ids.
46 this._index = {}; // Maps ids to downloads.
48 ["Downloads:GetList",
49 "Downloads:ClearAllDone",
50 "Downloads:Remove",
51 "Downloads:Pause",
52 "Downloads:Resume"].forEach((msgName) => {
53 ppmm.addMessageListener(msgName, this);
54 });
56 let self = this;
57 Task.spawn(function () {
58 let list = yield Downloads.getList(Downloads.ALL);
59 yield list.addView(self);
61 debug("view added to download list.");
62 }).then(null, Components.utils.reportError);
64 this._currentId = 0;
65 },
67 /**
68 * Returns a unique id for each download, hashing the url and the path.
69 */
70 downloadId: function(aDownload) {
71 let id = this._ids.get(aDownload, null);
72 if (!id) {
73 id = "download-" + this._currentId++;
74 this._ids.set(aDownload, id);
75 this._index[id] = aDownload;
76 }
77 return id;
78 },
80 getDownloadById: function(aId) {
81 return this._index[aId];
82 },
84 /**
85 * Converts a download object into a plain json object that we'll
86 * send to the DOM side.
87 */
88 jsonDownload: function(aDownload) {
89 let res = {
90 totalBytes: aDownload.totalBytes,
91 currentBytes: aDownload.currentBytes,
92 url: aDownload.source.url,
93 path: aDownload.target.path,
94 contentType: aDownload.contentType,
95 startTime: aDownload.startTime.getTime()
96 };
98 if (aDownload.error) {
99 res.error = aDownload.error;
100 }
102 res.id = this.downloadId(aDownload);
104 // The state of the download. Can be any of "downloading", "stopped",
105 // "succeeded", finalized".
107 // Default to "stopped"
108 res.state = "stopped";
109 if (!aDownload.stopped &&
110 !aDownload.canceled &&
111 !aDownload.succeeded &&
112 !aDownload.DownloadError) {
113 res.state = "downloading";
114 } else if (aDownload.succeeded) {
115 res.state = "succeeded";
116 }
117 return res;
118 },
120 /**
121 * download view methods.
122 */
123 onDownloadAdded: function(aDownload) {
124 let download = this.jsonDownload(aDownload);
125 debug("onDownloadAdded " + uneval(download));
126 ppmm.broadcastAsyncMessage("Downloads:Added", download);
127 },
129 onDownloadRemoved: function(aDownload) {
130 let download = this.jsonDownload(aDownload);
131 download.state = "finalized";
132 debug("onDownloadRemoved " + uneval(download));
133 ppmm.broadcastAsyncMessage("Downloads:Removed", download);
134 this._index[this._ids.get(aDownload)] = null;
135 this._ids.delete(aDownload);
136 },
138 onDownloadChanged: function(aDownload) {
139 let download = this.jsonDownload(aDownload);
140 debug("onDownloadChanged " + uneval(download));
141 ppmm.broadcastAsyncMessage("Downloads:Changed", download);
142 },
144 receiveMessage: function(aMessage) {
145 if (!aMessage.target.assertPermission("downloads")) {
146 debug("No 'downloads' permission!");
147 return;
148 }
150 debug("message: " + aMessage.name);
152 switch (aMessage.name) {
153 case "Downloads:GetList":
154 this.getList(aMessage.data, aMessage.target);
155 break;
156 case "Downloads:ClearAllDone":
157 this.clearAllDone(aMessage.data, aMessage.target);
158 break;
159 case "Downloads:Remove":
160 this.remove(aMessage.data, aMessage.target);
161 break;
162 case "Downloads:Pause":
163 this.pause(aMessage.data, aMessage.target);
164 break;
165 case "Downloads:Resume":
166 this.resume(aMessage.data, aMessage.target);
167 break;
168 default:
169 debug("Invalid message: " + aMessage.name);
170 }
171 },
173 getList: function(aData, aMm) {
174 debug("getList called!");
175 let self = this;
176 Task.spawn(function () {
177 let list = yield Downloads.getList(Downloads.ALL);
178 let downloads = yield list.getAll();
179 let res = [];
180 downloads.forEach((aDownload) => {
181 res.push(self.jsonDownload(aDownload));
182 });
183 aMm.sendAsyncMessage("Downloads:GetList:Return", res);
184 }).then(null, Components.utils.reportError);
185 },
187 clearAllDone: function(aData, aMm) {
188 debug("clearAllDone called!");
189 let self = this;
190 Task.spawn(function () {
191 let list = yield Downloads.getList(Downloads.ALL);
192 yield list.removeFinished();
193 list = yield Downloads.getList(Downloads.ALL);
194 let downloads = yield list.getAll();
195 let res = [];
196 downloads.forEach((aDownload) => {
197 res.push(self.jsonDownload(aDownload));
198 });
199 aMm.sendAsyncMessage("Downloads:ClearAllDone:Return", res);
200 }).then(null, Components.utils.reportError);
201 },
203 remove: function(aData, aMm) {
204 debug("remove id " + aData.id);
205 let download = this.getDownloadById(aData.id);
206 if (!download) {
207 sendPromiseMessage(aMm, "Downloads:Remove:Return",
208 aData, "NoSuchDownload");
209 return;
210 }
212 Task.spawn(function() {
213 yield download.finalize(true);
214 let list = yield Downloads.getList(Downloads.ALL);
215 yield list.remove(download);
216 }).then(
217 function() {
218 sendPromiseMessage(aMm, "Downloads:Remove:Return", aData);
219 },
220 function() {
221 sendPromiseMessage(aMm, "Downloads:Remove:Return",
222 aData, "RemoveError");
223 }
224 );
225 },
227 pause: function(aData, aMm) {
228 debug("pause id " + aData.id);
229 let download = this.getDownloadById(aData.id);
230 if (!download) {
231 sendPromiseMessage(aMm, "Downloads:Pause:Return",
232 aData, "NoSuchDownload");
233 return;
234 }
236 download.cancel().then(
237 function() {
238 sendPromiseMessage(aMm, "Downloads:Pause:Return", aData);
239 },
240 function() {
241 sendPromiseMessage(aMm, "Downloads:Pause:Return",
242 aData, "PauseError");
243 }
244 );
245 },
247 resume: function(aData, aMm) {
248 debug("resume id " + aData.id);
249 let download = this.getDownloadById(aData.id);
250 if (!download) {
251 sendPromiseMessage(aMm, "Downloads:Resume:Return",
252 aData, "NoSuchDownload");
253 return;
254 }
256 download.start().then(
257 function() {
258 sendPromiseMessage(aMm, "Downloads:Resume:Return", aData);
259 },
260 function() {
261 sendPromiseMessage(aMm, "Downloads:Resume:Return",
262 aData, "ResumeError");
263 }
264 );
265 }
266 };
268 DownloadsAPI.init();