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 /**
2 * Thin wrapper around a ChromeWorker that wraps postMessage/onmessage/onerror
3 * as promises.
4 *
5 * Not for public use yet.
6 */
8 "use strict";
10 this.EXPORTED_SYMBOLS = ["PromiseWorker"];
12 // The library of promises.
13 Components.utils.import("resource://gre/modules/Promise.jsm", this);
15 /**
16 * An implementation of queues (FIFO).
17 *
18 * The current implementation uses one array, runs in O(n ^ 2), and is optimized
19 * for the case in which queues are generally short.
20 */
21 let Queue = function Queue() {
22 this._array = [];
23 };
24 Queue.prototype = {
25 pop: function pop() {
26 return this._array.shift();
27 },
28 push: function push(x) {
29 return this._array.push(x);
30 },
31 isEmpty: function isEmpty() {
32 return this._array.length == 0;
33 }
34 };
36 /**
37 * An object responsible for dispatching messages to
38 * a chrome worker and routing the responses.
39 *
40 * @param {string} url The url containing the source code for this worker,
41 * as in constructor ChromeWorker.
42 * @param {Function} log A logging function.
43 *
44 * @constructor
45 */
46 function PromiseWorker(url, log) {
47 if (typeof url != "string") {
48 throw new TypeError("Expecting a string");
49 }
50 if (typeof log !== "function") {
51 throw new TypeError("log is expected to be a function");
52 }
53 this._log = log;
54 this._url = url;
56 /**
57 * The queue of deferred, waiting for the completion of their
58 * respective job by the worker.
59 *
60 * Each item in the list may contain an additional field |closure|,
61 * used to store strong references to value that must not be
62 * garbage-collected before the reply has been received (e.g.
63 * arrays).
64 *
65 * @type {Queue<{deferred:deferred, closure:*=}>}
66 */
67 this._queue = new Queue();
69 /**
70 * The number of the current message.
71 *
72 * Used for debugging purposes.
73 */
74 this._id = 0;
76 /**
77 * The instant at which the worker was launched.
78 */
79 this.launchTimeStamp = null;
81 /**
82 * Timestamps provided by the worker for statistics purposes.
83 */
84 this.workerTimeStamps = null;
85 }
86 PromiseWorker.prototype = {
87 /**
88 * Instantiate the worker lazily.
89 */
90 get _worker() {
91 delete this._worker;
92 let worker = new ChromeWorker(this._url);
93 let self = this;
94 Object.defineProperty(this, "_worker", {value:
95 worker
96 });
98 // We assume that we call to _worker for the purpose of calling
99 // postMessage().
100 this.launchTimeStamp = Date.now();
102 /**
103 * Receive errors that are not instances of OS.File.Error, propagate
104 * them to the listeners.
105 *
106 * The worker knows how to serialize errors that are instances
107 * of |OS.File.Error|. These are treated by |worker.onmessage|.
108 * However, for other errors, we rely on DOM's mechanism for
109 * serializing errors, which transmits these errors through
110 * |worker.onerror|.
111 *
112 * @param {Error} error Some JS error.
113 */
114 worker.onerror = function onerror(error) {
115 self._log("Received uncaught error from worker", error.message, error.filename, error.lineno);
116 error.preventDefault();
117 let {deferred} = self._queue.pop();
118 deferred.reject(error);
119 };
121 /**
122 * Receive messages from the worker, propagate them to the listeners.
123 *
124 * Messages must have one of the following shapes:
125 * - {ok: some_value} in case of success
126 * - {fail: some_error} in case of error, where
127 * some_error is an instance of |PromiseWorker.WorkerError|
128 *
129 * Messages may also contain a field |id| to help
130 * with debugging.
131 *
132 * Messages may also optionally contain a field |durationMs|, holding
133 * the duration of the function call in milliseconds.
134 *
135 * @param {*} msg The message received from the worker.
136 */
137 worker.onmessage = function onmessage(msg) {
138 self._log("Received message from worker", msg.data);
139 let handler = self._queue.pop();
140 let deferred = handler.deferred;
141 let data = msg.data;
142 if (data.id != handler.id) {
143 throw new Error("Internal error: expecting msg " + handler.id + ", " +
144 " got " + data.id + ": " + JSON.stringify(msg.data));
145 }
146 if ("timeStamps" in data) {
147 self.workerTimeStamps = data.timeStamps;
148 }
149 if ("ok" in data) {
150 // Pass the data to the listeners.
151 deferred.resolve(data);
152 } else if ("StopIteration" in data) {
153 // We have received a StopIteration error
154 deferred.reject(StopIteration);
155 } if ("fail" in data) {
156 // We have received an error that was serialized by the
157 // worker.
158 deferred.reject(new PromiseWorker.WorkerError(data.fail));
159 }
160 };
161 return worker;
162 },
164 /**
165 * Post a message to a worker.
166 *
167 * @param {string} fun The name of the function to call.
168 * @param {Array} array The contents of the message.
169 * @param {*=} closure An object holding references that should not be
170 * garbage-collected before the message treatment is complete.
171 *
172 * @return {promise}
173 */
174 post: function post(fun, array, closure) {
175 let deferred = Promise.defer();
176 let id = ++this._id;
177 let message = {fun: fun, args: array, id: id};
178 this._log("Posting message", message);
179 try {
180 this._worker.postMessage(message);
181 } catch (ex if typeof ex == "number") {
182 this._log("Could not post message", message, "due to xpcom error", ex);
183 // handle raw xpcom errors (see eg bug 961317)
184 return Promise.reject(new Components.Exception("Error in postMessage", ex));
185 } catch (ex) {
186 this._log("Could not post message", message, "due to error", ex);
187 return Promise.reject(ex);
188 }
190 this._queue.push({deferred:deferred, closure: closure, id: id});
191 this._log("Message posted");
192 return deferred.promise;
193 }
194 };
196 /**
197 * An error that has been serialized by the worker.
198 *
199 * @constructor
200 */
201 PromiseWorker.WorkerError = function WorkerError(data) {
202 this.data = data;
203 };
205 this.PromiseWorker = PromiseWorker;