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.
michael@0 | 1 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 4 | |
michael@0 | 5 | Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); |
michael@0 | 6 | Components.utils.import("resource://gre/modules/Services.jsm"); |
michael@0 | 7 | |
michael@0 | 8 | const Cc = Components.classes; |
michael@0 | 9 | const Ci = Components.interfaces; |
michael@0 | 10 | |
michael@0 | 11 | const PREF_APP_UPDATE_LASTUPDATETIME_FMT = "app.update.lastUpdateTime.%ID%"; |
michael@0 | 12 | const PREF_APP_UPDATE_TIMERMINIMUMDELAY = "app.update.timerMinimumDelay"; |
michael@0 | 13 | const PREF_APP_UPDATE_TIMERFIRSTINTERVAL = "app.update.timerFirstInterval"; |
michael@0 | 14 | const PREF_APP_UPDATE_LOG = "app.update.log"; |
michael@0 | 15 | |
michael@0 | 16 | const CATEGORY_UPDATE_TIMER = "update-timer"; |
michael@0 | 17 | |
michael@0 | 18 | XPCOMUtils.defineLazyGetter(this, "gLogEnabled", function tm_gLogEnabled() { |
michael@0 | 19 | return getPref("getBoolPref", PREF_APP_UPDATE_LOG, false); |
michael@0 | 20 | }); |
michael@0 | 21 | |
michael@0 | 22 | /** |
michael@0 | 23 | * Gets a preference value, handling the case where there is no default. |
michael@0 | 24 | * @param func |
michael@0 | 25 | * The name of the preference function to call, on nsIPrefBranch |
michael@0 | 26 | * @param preference |
michael@0 | 27 | * The name of the preference |
michael@0 | 28 | * @param defaultValue |
michael@0 | 29 | * The default value to return in the event the preference has |
michael@0 | 30 | * no setting |
michael@0 | 31 | * @returns The value of the preference, or undefined if there was no |
michael@0 | 32 | * user or default value. |
michael@0 | 33 | */ |
michael@0 | 34 | function getPref(func, preference, defaultValue) { |
michael@0 | 35 | try { |
michael@0 | 36 | return Services.prefs[func](preference); |
michael@0 | 37 | } |
michael@0 | 38 | catch (e) { |
michael@0 | 39 | } |
michael@0 | 40 | return defaultValue; |
michael@0 | 41 | } |
michael@0 | 42 | |
michael@0 | 43 | /** |
michael@0 | 44 | * Logs a string to the error console. |
michael@0 | 45 | * @param string |
michael@0 | 46 | * The string to write to the error console. |
michael@0 | 47 | */ |
michael@0 | 48 | function LOG(string) { |
michael@0 | 49 | if (gLogEnabled) { |
michael@0 | 50 | dump("*** UTM:SVC " + string + "\n"); |
michael@0 | 51 | Services.console.logStringMessage("UTM:SVC " + string); |
michael@0 | 52 | } |
michael@0 | 53 | } |
michael@0 | 54 | |
michael@0 | 55 | /** |
michael@0 | 56 | * A manager for timers. Manages timers that fire over long periods of time |
michael@0 | 57 | * (e.g. days, weeks, months). |
michael@0 | 58 | * @constructor |
michael@0 | 59 | */ |
michael@0 | 60 | function TimerManager() { |
michael@0 | 61 | Services.obs.addObserver(this, "xpcom-shutdown", false); |
michael@0 | 62 | } |
michael@0 | 63 | TimerManager.prototype = { |
michael@0 | 64 | /** |
michael@0 | 65 | * The Checker Timer |
michael@0 | 66 | */ |
michael@0 | 67 | _timer: null, |
michael@0 | 68 | |
michael@0 | 69 | /** |
michael@0 | 70 | * The Checker Timer minimum delay interval as specified by the |
michael@0 | 71 | * app.update.timerMinimumDelay pref. If the app.update.timerMinimumDelay |
michael@0 | 72 | * pref doesn't exist this will default to 120000. |
michael@0 | 73 | */ |
michael@0 | 74 | _timerMinimumDelay: null, |
michael@0 | 75 | |
michael@0 | 76 | /** |
michael@0 | 77 | * The set of registered timers. |
michael@0 | 78 | */ |
michael@0 | 79 | _timers: { }, |
michael@0 | 80 | |
michael@0 | 81 | /** |
michael@0 | 82 | * See nsIObserver.idl |
michael@0 | 83 | */ |
michael@0 | 84 | observe: function TM_observe(aSubject, aTopic, aData) { |
michael@0 | 85 | // Prevent setting the timer interval to a value of less than 30 seconds. |
michael@0 | 86 | var minInterval = 30000; |
michael@0 | 87 | // Prevent setting the first timer interval to a value of less than 10 |
michael@0 | 88 | // seconds. |
michael@0 | 89 | var minFirstInterval = 10000; |
michael@0 | 90 | switch (aTopic) { |
michael@0 | 91 | case "utm-test-init": |
michael@0 | 92 | // Enforce a minimum timer interval of 500 ms for tests and fall through |
michael@0 | 93 | // to profile-after-change to initialize the timer. |
michael@0 | 94 | minInterval = 500; |
michael@0 | 95 | minFirstInterval = 500; |
michael@0 | 96 | case "profile-after-change": |
michael@0 | 97 | // Cancel the timer if it has already been initialized. This is primarily |
michael@0 | 98 | // for tests. |
michael@0 | 99 | this._timerMinimumDelay = Math.max(1000 * getPref("getIntPref", PREF_APP_UPDATE_TIMERMINIMUMDELAY, 120), |
michael@0 | 100 | minInterval); |
michael@0 | 101 | let firstInterval = Math.max(getPref("getIntPref", PREF_APP_UPDATE_TIMERFIRSTINTERVAL, |
michael@0 | 102 | this._timerMinimumDelay), minFirstInterval); |
michael@0 | 103 | this._canEnsureTimer = true; |
michael@0 | 104 | this._ensureTimer(firstInterval); |
michael@0 | 105 | break; |
michael@0 | 106 | case "xpcom-shutdown": |
michael@0 | 107 | Services.obs.removeObserver(this, "xpcom-shutdown"); |
michael@0 | 108 | |
michael@0 | 109 | // Release everything we hold onto. |
michael@0 | 110 | this._cancelTimer(); |
michael@0 | 111 | for (var timerID in this._timers) |
michael@0 | 112 | delete this._timers[timerID]; |
michael@0 | 113 | this._timers = null; |
michael@0 | 114 | break; |
michael@0 | 115 | } |
michael@0 | 116 | }, |
michael@0 | 117 | |
michael@0 | 118 | /** |
michael@0 | 119 | * Called when the checking timer fires. |
michael@0 | 120 | * |
michael@0 | 121 | * We only fire one notification each time, so that the operations are |
michael@0 | 122 | * staggered. We don't want too many to happen at once, which could |
michael@0 | 123 | * negatively impact responsiveness. |
michael@0 | 124 | * |
michael@0 | 125 | * @param timer |
michael@0 | 126 | * The checking timer that fired. |
michael@0 | 127 | */ |
michael@0 | 128 | notify: function TM_notify(timer) { |
michael@0 | 129 | var nextDelay = null; |
michael@0 | 130 | function updateNextDelay(delay) { |
michael@0 | 131 | if (nextDelay === null || delay < nextDelay) |
michael@0 | 132 | nextDelay = delay; |
michael@0 | 133 | } |
michael@0 | 134 | |
michael@0 | 135 | // Each timer calls tryFire(), which figures out which is the one that |
michael@0 | 136 | // wanted to be called earliest. That one will be fired; the others are |
michael@0 | 137 | // skipped and will be done later. |
michael@0 | 138 | var now = Math.round(Date.now() / 1000); |
michael@0 | 139 | |
michael@0 | 140 | var callbackToFire = null; |
michael@0 | 141 | var earliestIntendedTime = null; |
michael@0 | 142 | var skippedFirings = false; |
michael@0 | 143 | function tryFire(callback, intendedTime) { |
michael@0 | 144 | var selected = false; |
michael@0 | 145 | if (intendedTime <= now) { |
michael@0 | 146 | if (intendedTime < earliestIntendedTime || |
michael@0 | 147 | earliestIntendedTime === null) { |
michael@0 | 148 | callbackToFire = callback; |
michael@0 | 149 | earliestIntendedTime = intendedTime; |
michael@0 | 150 | selected = true; |
michael@0 | 151 | } |
michael@0 | 152 | else if (earliestIntendedTime !== null) |
michael@0 | 153 | skippedFirings = true; |
michael@0 | 154 | } |
michael@0 | 155 | // We do not need to updateNextDelay for the timer that actually fires; |
michael@0 | 156 | // we'll update right after it fires, with the proper intended time. |
michael@0 | 157 | // Note that we might select one, then select another later (with an |
michael@0 | 158 | // earlier intended time); it is still ok that we did not update for |
michael@0 | 159 | // the first one, since if we have skipped firings, the next delay |
michael@0 | 160 | // will be the minimum delay anyhow. |
michael@0 | 161 | if (!selected) |
michael@0 | 162 | updateNextDelay(intendedTime - now); |
michael@0 | 163 | } |
michael@0 | 164 | |
michael@0 | 165 | var catMan = Cc["@mozilla.org/categorymanager;1"]. |
michael@0 | 166 | getService(Ci.nsICategoryManager); |
michael@0 | 167 | var entries = catMan.enumerateCategory(CATEGORY_UPDATE_TIMER); |
michael@0 | 168 | while (entries.hasMoreElements()) { |
michael@0 | 169 | let entry = entries.getNext().QueryInterface(Ci.nsISupportsCString).data; |
michael@0 | 170 | let value = catMan.getCategoryEntry(CATEGORY_UPDATE_TIMER, entry); |
michael@0 | 171 | let [cid, method, timerID, prefInterval, defaultInterval] = value.split(","); |
michael@0 | 172 | |
michael@0 | 173 | defaultInterval = parseInt(defaultInterval); |
michael@0 | 174 | // cid and method are validated below when calling notify. |
michael@0 | 175 | if (!timerID || !defaultInterval || isNaN(defaultInterval)) { |
michael@0 | 176 | LOG("TimerManager:notify - update-timer category registered" + |
michael@0 | 177 | (cid ? " for " + cid : "") + " without required parameters - " + |
michael@0 | 178 | "skipping"); |
michael@0 | 179 | continue; |
michael@0 | 180 | } |
michael@0 | 181 | |
michael@0 | 182 | let interval = getPref("getIntPref", prefInterval, defaultInterval); |
michael@0 | 183 | let prefLastUpdate = PREF_APP_UPDATE_LASTUPDATETIME_FMT.replace(/%ID%/, |
michael@0 | 184 | timerID); |
michael@0 | 185 | // Initialize the last update time to 0 when the preference isn't set so |
michael@0 | 186 | // the timer will be notified soon after a new profile's first use. |
michael@0 | 187 | let lastUpdateTime = getPref("getIntPref", prefLastUpdate, 0); |
michael@0 | 188 | |
michael@0 | 189 | // If the last update time is greater than the current time then reset |
michael@0 | 190 | // it to 0 and the timer manager will correct the value when it fires |
michael@0 | 191 | // next for this consumer. |
michael@0 | 192 | if (lastUpdateTime > now) |
michael@0 | 193 | lastUpdateTime = 0; |
michael@0 | 194 | |
michael@0 | 195 | if (lastUpdateTime == 0) |
michael@0 | 196 | Services.prefs.setIntPref(prefLastUpdate, lastUpdateTime); |
michael@0 | 197 | |
michael@0 | 198 | tryFire(function() { |
michael@0 | 199 | try { |
michael@0 | 200 | Components.classes[cid][method](Ci.nsITimerCallback).notify(timer); |
michael@0 | 201 | LOG("TimerManager:notify - notified " + cid); |
michael@0 | 202 | } |
michael@0 | 203 | catch (e) { |
michael@0 | 204 | LOG("TimerManager:notify - error notifying component id: " + |
michael@0 | 205 | cid + " ,error: " + e); |
michael@0 | 206 | } |
michael@0 | 207 | lastUpdateTime = now; |
michael@0 | 208 | Services.prefs.setIntPref(prefLastUpdate, lastUpdateTime); |
michael@0 | 209 | updateNextDelay(lastUpdateTime + interval - now); |
michael@0 | 210 | }, lastUpdateTime + interval); |
michael@0 | 211 | } |
michael@0 | 212 | |
michael@0 | 213 | for (let _timerID in this._timers) { |
michael@0 | 214 | let timerID = _timerID; // necessary for the closure to work properly |
michael@0 | 215 | let timerData = this._timers[timerID]; |
michael@0 | 216 | // If the last update time is greater than the current time then reset |
michael@0 | 217 | // it to 0 and the timer manager will correct the value when it fires |
michael@0 | 218 | // next for this consumer. |
michael@0 | 219 | if (timerData.lastUpdateTime > now) { |
michael@0 | 220 | let prefLastUpdate = PREF_APP_UPDATE_LASTUPDATETIME_FMT.replace(/%ID%/, timerID); |
michael@0 | 221 | timerData.lastUpdateTime = 0; |
michael@0 | 222 | Services.prefs.setIntPref(prefLastUpdate, timerData.lastUpdateTime); |
michael@0 | 223 | } |
michael@0 | 224 | tryFire(function() { |
michael@0 | 225 | if (timerData.callback && timerData.callback.notify) { |
michael@0 | 226 | try { |
michael@0 | 227 | timerData.callback.notify(timer); |
michael@0 | 228 | LOG("TimerManager:notify - notified timerID: " + timerID); |
michael@0 | 229 | } |
michael@0 | 230 | catch (e) { |
michael@0 | 231 | LOG("TimerManager:notify - error notifying timerID: " + timerID + |
michael@0 | 232 | ", error: " + e); |
michael@0 | 233 | } |
michael@0 | 234 | } |
michael@0 | 235 | else { |
michael@0 | 236 | LOG("TimerManager:notify - timerID: " + timerID + " doesn't " + |
michael@0 | 237 | "implement nsITimerCallback - skipping"); |
michael@0 | 238 | } |
michael@0 | 239 | lastUpdateTime = now; |
michael@0 | 240 | timerData.lastUpdateTime = lastUpdateTime; |
michael@0 | 241 | let prefLastUpdate = PREF_APP_UPDATE_LASTUPDATETIME_FMT.replace(/%ID%/, timerID); |
michael@0 | 242 | Services.prefs.setIntPref(prefLastUpdate, lastUpdateTime); |
michael@0 | 243 | updateNextDelay(timerData.lastUpdateTime + timerData.interval - now); |
michael@0 | 244 | }, timerData.lastUpdateTime + timerData.interval); |
michael@0 | 245 | } |
michael@0 | 246 | |
michael@0 | 247 | if (callbackToFire) |
michael@0 | 248 | callbackToFire(); |
michael@0 | 249 | |
michael@0 | 250 | if (nextDelay !== null) { |
michael@0 | 251 | if (skippedFirings) |
michael@0 | 252 | timer.delay = this._timerMinimumDelay; |
michael@0 | 253 | else |
michael@0 | 254 | timer.delay = Math.max(nextDelay * 1000, this._timerMinimumDelay); |
michael@0 | 255 | this.lastTimerReset = Date.now(); |
michael@0 | 256 | } else { |
michael@0 | 257 | this._cancelTimer(); |
michael@0 | 258 | } |
michael@0 | 259 | }, |
michael@0 | 260 | |
michael@0 | 261 | /** |
michael@0 | 262 | * Starts the timer, if necessary, and ensures that it will fire soon enough |
michael@0 | 263 | * to happen after time |interval| (in milliseconds). |
michael@0 | 264 | */ |
michael@0 | 265 | _ensureTimer: function(interval) { |
michael@0 | 266 | if (!this._canEnsureTimer) |
michael@0 | 267 | return; |
michael@0 | 268 | if (!this._timer) { |
michael@0 | 269 | this._timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); |
michael@0 | 270 | this._timer.initWithCallback(this, interval, |
michael@0 | 271 | Ci.nsITimer.TYPE_REPEATING_SLACK); |
michael@0 | 272 | this.lastTimerReset = Date.now(); |
michael@0 | 273 | } else { |
michael@0 | 274 | if (Date.now() + interval < this.lastTimerReset + this._timer.delay) |
michael@0 | 275 | this._timer.delay = Math.max(this.lastTimerReset + interval - Date.now(), 0); |
michael@0 | 276 | } |
michael@0 | 277 | }, |
michael@0 | 278 | |
michael@0 | 279 | /** |
michael@0 | 280 | * Stops the timer, if it is running. |
michael@0 | 281 | */ |
michael@0 | 282 | _cancelTimer: function() { |
michael@0 | 283 | if (this._timer) { |
michael@0 | 284 | this._timer.cancel(); |
michael@0 | 285 | this._timer = null; |
michael@0 | 286 | } |
michael@0 | 287 | }, |
michael@0 | 288 | |
michael@0 | 289 | /** |
michael@0 | 290 | * See nsIUpdateTimerManager.idl |
michael@0 | 291 | */ |
michael@0 | 292 | registerTimer: function TM_registerTimer(id, callback, interval) { |
michael@0 | 293 | LOG("TimerManager:registerTimer - id: " + id); |
michael@0 | 294 | let prefLastUpdate = PREF_APP_UPDATE_LASTUPDATETIME_FMT.replace(/%ID%/, id); |
michael@0 | 295 | // Initialize the last update time to 0 when the preference isn't set so |
michael@0 | 296 | // the timer will be notified soon after a new profile's first use. |
michael@0 | 297 | let lastUpdateTime = getPref("getIntPref", prefLastUpdate, 0); |
michael@0 | 298 | let now = Math.round(Date.now() / 1000); |
michael@0 | 299 | if (lastUpdateTime > now) |
michael@0 | 300 | lastUpdateTime = 0; |
michael@0 | 301 | if (lastUpdateTime == 0) |
michael@0 | 302 | Services.prefs.setIntPref(prefLastUpdate, lastUpdateTime); |
michael@0 | 303 | this._timers[id] = { callback : callback, |
michael@0 | 304 | interval : interval, |
michael@0 | 305 | lastUpdateTime : lastUpdateTime }; |
michael@0 | 306 | |
michael@0 | 307 | this._ensureTimer(interval * 1000); |
michael@0 | 308 | }, |
michael@0 | 309 | |
michael@0 | 310 | classID: Components.ID("{B322A5C0-A419-484E-96BA-D7182163899F}"), |
michael@0 | 311 | QueryInterface: XPCOMUtils.generateQI([Ci.nsIUpdateTimerManager, |
michael@0 | 312 | Ci.nsITimerCallback, |
michael@0 | 313 | Ci.nsIObserver]) |
michael@0 | 314 | }; |
michael@0 | 315 | |
michael@0 | 316 | this.NSGetFactory = XPCOMUtils.generateNSGetFactory([TimerManager]); |