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 | 'use strict'; |
michael@0 | 5 | |
michael@0 | 6 | const { Cc, Ci, Cr } = require('chrome'), |
michael@0 | 7 | { Trait } = require('../deprecated/traits'), |
michael@0 | 8 | { List } = require('../deprecated/list'), |
michael@0 | 9 | { EventEmitter } = require('../deprecated/events'), |
michael@0 | 10 | { WindowTabs, WindowTabTracker } = require('./tabs-firefox'), |
michael@0 | 11 | { WindowDom } = require('./dom'), |
michael@0 | 12 | { WindowLoader } = require('./loader'), |
michael@0 | 13 | { isBrowser, getWindowDocShell, windows: windowIterator } = require('../window/utils'), |
michael@0 | 14 | { Options } = require('../tabs/common'), |
michael@0 | 15 | apiUtils = require('../deprecated/api-utils'), |
michael@0 | 16 | unload = require('../system/unload'), |
michael@0 | 17 | windowUtils = require('../deprecated/window-utils'), |
michael@0 | 18 | { WindowTrackerTrait } = windowUtils, |
michael@0 | 19 | { ns } = require('../core/namespace'), |
michael@0 | 20 | { observer: windowObserver } = require('./observer'), |
michael@0 | 21 | { getOwnerWindow } = require('../private-browsing/window/utils'); |
michael@0 | 22 | const { windowNS } = require('../window/namespace'); |
michael@0 | 23 | const { isPrivateBrowsingSupported } = require('../self'); |
michael@0 | 24 | const { ignoreWindow } = require('sdk/private-browsing/utils'); |
michael@0 | 25 | const { viewFor } = require('../view/core'); |
michael@0 | 26 | |
michael@0 | 27 | /** |
michael@0 | 28 | * Window trait composes safe wrappers for browser window that are E10S |
michael@0 | 29 | * compatible. |
michael@0 | 30 | */ |
michael@0 | 31 | const BrowserWindowTrait = Trait.compose( |
michael@0 | 32 | EventEmitter, |
michael@0 | 33 | WindowDom.resolve({ close: '_close' }), |
michael@0 | 34 | WindowTabs, |
michael@0 | 35 | WindowTabTracker, |
michael@0 | 36 | WindowLoader, |
michael@0 | 37 | /* WindowSidebars, */ |
michael@0 | 38 | Trait.compose({ |
michael@0 | 39 | _emit: Trait.required, |
michael@0 | 40 | _close: Trait.required, |
michael@0 | 41 | _load: Trait.required, |
michael@0 | 42 | /** |
michael@0 | 43 | * Constructor returns wrapper of the specified chrome window. |
michael@0 | 44 | * @param {nsIWindow} window |
michael@0 | 45 | */ |
michael@0 | 46 | constructor: function BrowserWindow(options) { |
michael@0 | 47 | // Register this window ASAP, in order to avoid loop that would try |
michael@0 | 48 | // to create this window instance over and over (see bug 648244) |
michael@0 | 49 | windows.push(this); |
michael@0 | 50 | |
michael@0 | 51 | // make sure we don't have unhandled errors |
michael@0 | 52 | this.on('error', console.exception.bind(console)); |
michael@0 | 53 | |
michael@0 | 54 | if ('onOpen' in options) |
michael@0 | 55 | this.on('open', options.onOpen); |
michael@0 | 56 | if ('onClose' in options) |
michael@0 | 57 | this.on('close', options.onClose); |
michael@0 | 58 | if ('onActivate' in options) |
michael@0 | 59 | this.on('activate', options.onActivate); |
michael@0 | 60 | if ('onDeactivate' in options) |
michael@0 | 61 | this.on('deactivate', options.onDeactivate); |
michael@0 | 62 | if ('window' in options) |
michael@0 | 63 | this._window = options.window; |
michael@0 | 64 | |
michael@0 | 65 | if ('tabs' in options) { |
michael@0 | 66 | this._tabOptions = Array.isArray(options.tabs) ? |
michael@0 | 67 | options.tabs.map(Options) : |
michael@0 | 68 | [ Options(options.tabs) ]; |
michael@0 | 69 | } |
michael@0 | 70 | else if ('url' in options) { |
michael@0 | 71 | this._tabOptions = [ Options(options.url) ]; |
michael@0 | 72 | } |
michael@0 | 73 | |
michael@0 | 74 | this._isPrivate = isPrivateBrowsingSupported && !!options.isPrivate; |
michael@0 | 75 | |
michael@0 | 76 | this._load(); |
michael@0 | 77 | |
michael@0 | 78 | windowNS(this._public).window = this._window; |
michael@0 | 79 | getOwnerWindow.implement(this._public, getChromeWindow); |
michael@0 | 80 | viewFor.implement(this._public, getChromeWindow); |
michael@0 | 81 | |
michael@0 | 82 | return this; |
michael@0 | 83 | }, |
michael@0 | 84 | destroy: function () this._onUnload(), |
michael@0 | 85 | _tabOptions: [], |
michael@0 | 86 | _onLoad: function() { |
michael@0 | 87 | try { |
michael@0 | 88 | this._initWindowTabTracker(); |
michael@0 | 89 | this._loaded = true; |
michael@0 | 90 | } |
michael@0 | 91 | catch(e) { |
michael@0 | 92 | this._emit('error', e); |
michael@0 | 93 | } |
michael@0 | 94 | |
michael@0 | 95 | this._emitOnObject(browserWindows, 'open', this._public); |
michael@0 | 96 | }, |
michael@0 | 97 | _onUnload: function() { |
michael@0 | 98 | if (!this._window) |
michael@0 | 99 | return; |
michael@0 | 100 | if (this._loaded) |
michael@0 | 101 | this._destroyWindowTabTracker(); |
michael@0 | 102 | |
michael@0 | 103 | this._emitOnObject(browserWindows, 'close', this._public); |
michael@0 | 104 | this._window = null; |
michael@0 | 105 | windowNS(this._public).window = null; |
michael@0 | 106 | // Removing reference from the windows array. |
michael@0 | 107 | windows.splice(windows.indexOf(this), 1); |
michael@0 | 108 | this._removeAllListeners(); |
michael@0 | 109 | }, |
michael@0 | 110 | close: function close(callback) { |
michael@0 | 111 | // maybe we should deprecate this with message ? |
michael@0 | 112 | if (callback) this.on('close', callback); |
michael@0 | 113 | return this._close(); |
michael@0 | 114 | } |
michael@0 | 115 | }) |
michael@0 | 116 | ); |
michael@0 | 117 | |
michael@0 | 118 | /** |
michael@0 | 119 | * Gets a `BrowserWindowTrait` for the given `chromeWindow` if previously |
michael@0 | 120 | * registered, `null` otherwise. |
michael@0 | 121 | */ |
michael@0 | 122 | function getRegisteredWindow(chromeWindow) { |
michael@0 | 123 | for each (let window in windows) { |
michael@0 | 124 | if (chromeWindow === window._window) |
michael@0 | 125 | return window; |
michael@0 | 126 | } |
michael@0 | 127 | |
michael@0 | 128 | return null; |
michael@0 | 129 | } |
michael@0 | 130 | |
michael@0 | 131 | /** |
michael@0 | 132 | * Wrapper for `BrowserWindowTrait`. Creates new instance if wrapper for |
michael@0 | 133 | * window doesn't exists yet. If wrapper already exists then returns it |
michael@0 | 134 | * instead. |
michael@0 | 135 | * @params {Object} options |
michael@0 | 136 | * Options that are passed to the the `BrowserWindowTrait` |
michael@0 | 137 | * @returns {BrowserWindow} |
michael@0 | 138 | * @see BrowserWindowTrait |
michael@0 | 139 | */ |
michael@0 | 140 | function BrowserWindow(options) { |
michael@0 | 141 | let window = null; |
michael@0 | 142 | |
michael@0 | 143 | if ("window" in options) |
michael@0 | 144 | window = getRegisteredWindow(options.window); |
michael@0 | 145 | |
michael@0 | 146 | return (window || BrowserWindowTrait(options))._public; |
michael@0 | 147 | } |
michael@0 | 148 | // to have proper `instanceof` behavior will go away when #596248 is fixed. |
michael@0 | 149 | BrowserWindow.prototype = BrowserWindowTrait.prototype; |
michael@0 | 150 | exports.BrowserWindow = BrowserWindow; |
michael@0 | 151 | |
michael@0 | 152 | const windows = []; |
michael@0 | 153 | |
michael@0 | 154 | const browser = ns(); |
michael@0 | 155 | |
michael@0 | 156 | function onWindowActivation (chromeWindow, event) { |
michael@0 | 157 | if (!isBrowser(chromeWindow)) return; // Ignore if it's not a browser window. |
michael@0 | 158 | |
michael@0 | 159 | let window = getRegisteredWindow(chromeWindow); |
michael@0 | 160 | |
michael@0 | 161 | if (window) |
michael@0 | 162 | window._emit(event.type, window._public); |
michael@0 | 163 | else |
michael@0 | 164 | window = BrowserWindowTrait({ window: chromeWindow }); |
michael@0 | 165 | |
michael@0 | 166 | browser(browserWindows).internals._emit(event.type, window._public); |
michael@0 | 167 | } |
michael@0 | 168 | |
michael@0 | 169 | windowObserver.on("activate", onWindowActivation); |
michael@0 | 170 | windowObserver.on("deactivate", onWindowActivation); |
michael@0 | 171 | |
michael@0 | 172 | /** |
michael@0 | 173 | * `BrowserWindows` trait is composed out of `List` trait and it represents |
michael@0 | 174 | * "live" list of currently open browser windows. Instance mutates itself |
michael@0 | 175 | * whenever new browser window gets opened / closed. |
michael@0 | 176 | */ |
michael@0 | 177 | // Very stupid to resolve all `toStrings` but this will be fixed by #596248 |
michael@0 | 178 | const browserWindows = Trait.resolve({ toString: null }).compose( |
michael@0 | 179 | List.resolve({ constructor: '_initList' }), |
michael@0 | 180 | EventEmitter.resolve({ toString: null }), |
michael@0 | 181 | WindowTrackerTrait.resolve({ constructor: '_initTracker', toString: null }), |
michael@0 | 182 | Trait.compose({ |
michael@0 | 183 | _emit: Trait.required, |
michael@0 | 184 | _add: Trait.required, |
michael@0 | 185 | _remove: Trait.required, |
michael@0 | 186 | |
michael@0 | 187 | // public API |
michael@0 | 188 | |
michael@0 | 189 | /** |
michael@0 | 190 | * Constructor creates instance of `Windows` that represents live list of open |
michael@0 | 191 | * windows. |
michael@0 | 192 | */ |
michael@0 | 193 | constructor: function BrowserWindows() { |
michael@0 | 194 | browser(this._public).internals = this; |
michael@0 | 195 | |
michael@0 | 196 | this._trackedWindows = []; |
michael@0 | 197 | this._initList(); |
michael@0 | 198 | this._initTracker(); |
michael@0 | 199 | unload.ensure(this, "_destructor"); |
michael@0 | 200 | }, |
michael@0 | 201 | _destructor: function _destructor() { |
michael@0 | 202 | this._removeAllListeners('open'); |
michael@0 | 203 | this._removeAllListeners('close'); |
michael@0 | 204 | this._removeAllListeners('activate'); |
michael@0 | 205 | this._removeAllListeners('deactivate'); |
michael@0 | 206 | this._clear(); |
michael@0 | 207 | |
michael@0 | 208 | delete browser(this._public).internals; |
michael@0 | 209 | }, |
michael@0 | 210 | /** |
michael@0 | 211 | * This property represents currently active window. |
michael@0 | 212 | * Property is non-enumerable, in order to preserve array like enumeration. |
michael@0 | 213 | * @type {Window|null} |
michael@0 | 214 | */ |
michael@0 | 215 | get activeWindow() { |
michael@0 | 216 | let window = windowUtils.activeBrowserWindow; |
michael@0 | 217 | // Bug 834961: ignore private windows when they are not supported |
michael@0 | 218 | if (ignoreWindow(window)) |
michael@0 | 219 | window = windowIterator()[0]; |
michael@0 | 220 | return window ? BrowserWindow({window: window}) : null; |
michael@0 | 221 | }, |
michael@0 | 222 | open: function open(options) { |
michael@0 | 223 | if (typeof options === "string") { |
michael@0 | 224 | // `tabs` option is under review and may be removed. |
michael@0 | 225 | options = { |
michael@0 | 226 | tabs: [Options(options)], |
michael@0 | 227 | isPrivate: isPrivateBrowsingSupported && options.isPrivate |
michael@0 | 228 | }; |
michael@0 | 229 | } |
michael@0 | 230 | return BrowserWindow(options); |
michael@0 | 231 | }, |
michael@0 | 232 | |
michael@0 | 233 | /** |
michael@0 | 234 | * Internal listener which is called whenever new window gets open. |
michael@0 | 235 | * Creates wrapper and adds to this list. |
michael@0 | 236 | * @param {nsIWindow} chromeWindow |
michael@0 | 237 | */ |
michael@0 | 238 | _onTrack: function _onTrack(chromeWindow) { |
michael@0 | 239 | if (!isBrowser(chromeWindow)) return; |
michael@0 | 240 | let window = BrowserWindow({ window: chromeWindow }); |
michael@0 | 241 | this._add(window); |
michael@0 | 242 | this._emit('open', window); |
michael@0 | 243 | }, |
michael@0 | 244 | |
michael@0 | 245 | /** |
michael@0 | 246 | * Internal listener which is called whenever window gets closed. |
michael@0 | 247 | * Cleans up references and removes wrapper from this list. |
michael@0 | 248 | * @param {nsIWindow} window |
michael@0 | 249 | */ |
michael@0 | 250 | _onUntrack: function _onUntrack(chromeWindow) { |
michael@0 | 251 | if (!isBrowser(chromeWindow)) return; |
michael@0 | 252 | let window = BrowserWindow({ window: chromeWindow }); |
michael@0 | 253 | this._remove(window); |
michael@0 | 254 | this._emit('close', window); |
michael@0 | 255 | |
michael@0 | 256 | // Bug 724404: do not leak this module and linked windows: |
michael@0 | 257 | // We have to do it on untrack and not only when `_onUnload` is called |
michael@0 | 258 | // when windows are closed, otherwise, we will leak on addon disabling. |
michael@0 | 259 | window.destroy(); |
michael@0 | 260 | } |
michael@0 | 261 | }).resolve({ toString: null }) |
michael@0 | 262 | )(); |
michael@0 | 263 | |
michael@0 | 264 | function getChromeWindow(window) { |
michael@0 | 265 | return windowNS(window).window; |
michael@0 | 266 | } |
michael@0 | 267 | |
michael@0 | 268 | exports.browserWindows = browserWindows; |