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 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 et sw=2 tw=80 filetype=javascript: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 /**
8 * Handles serialization of Download objects and persistence into a file, so
9 * that the state of downloads can be restored across sessions.
10 *
11 * The file is stored in JSON format, without indentation. With indentation
12 * applied, the file would look like this:
13 *
14 * {
15 * "list": [
16 * {
17 * "source": "http://www.example.com/download.txt",
18 * "target": "/home/user/Downloads/download.txt"
19 * },
20 * {
21 * "source": {
22 * "url": "http://www.example.com/download.txt",
23 * "referrer": "http://www.example.com/referrer.html"
24 * },
25 * "target": "/home/user/Downloads/download-2.txt"
26 * }
27 * ]
28 * }
29 */
31 "use strict";
33 this.EXPORTED_SYMBOLS = [
34 "DownloadStore",
35 ];
37 ////////////////////////////////////////////////////////////////////////////////
38 //// Globals
40 const Cc = Components.classes;
41 const Ci = Components.interfaces;
42 const Cu = Components.utils;
43 const Cr = Components.results;
45 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
47 XPCOMUtils.defineLazyModuleGetter(this, "Downloads",
48 "resource://gre/modules/Downloads.jsm");
49 XPCOMUtils.defineLazyModuleGetter(this, "OS",
50 "resource://gre/modules/osfile.jsm")
51 XPCOMUtils.defineLazyModuleGetter(this, "Task",
52 "resource://gre/modules/Task.jsm");
54 XPCOMUtils.defineLazyGetter(this, "gTextDecoder", function () {
55 return new TextDecoder();
56 });
58 XPCOMUtils.defineLazyGetter(this, "gTextEncoder", function () {
59 return new TextEncoder();
60 });
62 ////////////////////////////////////////////////////////////////////////////////
63 //// DownloadStore
65 /**
66 * Handles serialization of Download objects and persistence into a file, so
67 * that the state of downloads can be restored across sessions.
68 *
69 * @param aList
70 * DownloadList object to be populated or serialized.
71 * @param aPath
72 * String containing the file path where data should be saved.
73 */
74 this.DownloadStore = function (aList, aPath)
75 {
76 this.list = aList;
77 this.path = aPath;
78 }
80 this.DownloadStore.prototype = {
81 /**
82 * DownloadList object to be populated or serialized.
83 */
84 list: null,
86 /**
87 * String containing the file path where data should be saved.
88 */
89 path: "",
91 /**
92 * This function is called with a Download object as its first argument, and
93 * should return true if the item should be saved.
94 */
95 onsaveitem: () => true,
97 /**
98 * Loads persistent downloads from the file to the list.
99 *
100 * @return {Promise}
101 * @resolves When the operation finished successfully.
102 * @rejects JavaScript exception.
103 */
104 load: function DS_load()
105 {
106 return Task.spawn(function task_DS_load() {
107 let bytes;
108 try {
109 bytes = yield OS.File.read(this.path);
110 } catch (ex if ex instanceof OS.File.Error && ex.becauseNoSuchFile) {
111 // If the file does not exist, there are no downloads to load.
112 return;
113 }
115 let storeData = JSON.parse(gTextDecoder.decode(bytes));
117 // Create live downloads based on the static snapshot.
118 for (let downloadData of storeData.list) {
119 try {
120 let download = yield Downloads.createDownload(downloadData);
121 try {
122 if (!download.succeeded && !download.canceled && !download.error) {
123 // Try to restart the download if it was in progress during the
124 // previous session.
125 download.start();
126 } else {
127 // If the download was not in progress, try to update the current
128 // progress from disk. This is relevant in case we retained
129 // partially downloaded data.
130 yield download.refresh();
131 }
132 } finally {
133 // Add the download to the list if we succeeded in creating it,
134 // after we have updated its initial state.
135 yield this.list.add(download);
136 }
137 } catch (ex) {
138 // If an item is unrecognized, don't prevent others from being loaded.
139 Cu.reportError(ex);
140 }
141 }
142 }.bind(this));
143 },
145 /**
146 * Saves persistent downloads from the list to the file.
147 *
148 * If an error occurs, the previous file is not deleted.
149 *
150 * @return {Promise}
151 * @resolves When the operation finished successfully.
152 * @rejects JavaScript exception.
153 */
154 save: function DS_save()
155 {
156 return Task.spawn(function task_DS_save() {
157 let downloads = yield this.list.getAll();
159 // Take a static snapshot of the current state of all the downloads.
160 let storeData = { list: [] };
161 let atLeastOneDownload = false;
162 for (let download of downloads) {
163 try {
164 if (!this.onsaveitem(download)) {
165 continue;
166 }
167 storeData.list.push(download.toSerializable());
168 atLeastOneDownload = true;
169 } catch (ex) {
170 // If an item cannot be converted to a serializable form, don't
171 // prevent others from being saved.
172 Cu.reportError(ex);
173 }
174 }
176 if (atLeastOneDownload) {
177 // Create or overwrite the file if there are downloads to save.
178 let bytes = gTextEncoder.encode(JSON.stringify(storeData));
179 yield OS.File.writeAtomic(this.path, bytes,
180 { tmpPath: this.path + ".tmp" });
181 } else {
182 // Remove the file if there are no downloads to save at all.
183 try {
184 yield OS.File.remove(this.path);
185 } catch (ex if ex instanceof OS.File.Error &&
186 (ex.becauseNoSuchFile || ex.becauseAccessDenied)) {
187 // On Windows, we may get an access denied error instead of a no such
188 // file error if the file existed before, and was recently deleted.
189 }
190 }
191 }.bind(this));
192 },
193 };