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/. */
4 "use strict";
6 module.metadata = {
7 "stability": "stable"
8 };
10 const { Class } = require('./core/heritage');
11 const { on, emit, off, setListeners } = require('./event/core');
12 const { filter, pipe, map, merge: streamMerge, stripListeners } = require('./event/utils');
13 const { detach, attach, destroy, WorkerHost } = require('./content/utils');
14 const { Worker } = require('./content/worker');
15 const { Disposable } = require('./core/disposable');
16 const { WeakReference } = require('./core/reference');
17 const { EventTarget } = require('./event/target');
18 const { unload } = require('./system/unload');
19 const { events, streamEventsFrom } = require('./content/events');
20 const { getAttachEventType } = require('./content/utils');
21 const { window } = require('./addon/window');
22 const { getParentWindow } = require('./window/utils');
23 const { create: makeFrame, getDocShell } = require('./frame/utils');
24 const { contract } = require('./util/contract');
25 const { contract: loaderContract } = require('./content/loader');
26 const { has } = require('./util/array');
27 const { Rules } = require('./util/rules');
28 const { merge } = require('./util/object');
30 const views = WeakMap();
31 const workers = WeakMap();
32 const pages = WeakMap();
34 const readyEventNames = [
35 'DOMContentLoaded',
36 'document-element-inserted',
37 'load'
38 ];
40 function workerFor(page) workers.get(page)
41 function pageFor(view) pages.get(view)
42 function viewFor(page) views.get(page)
43 function isDisposed (page) !views.get(page, false)
45 let pageContract = contract(merge({
46 allow: {
47 is: ['object', 'undefined', 'null'],
48 map: function (allow) { return { script: !allow || allow.script !== false }}
49 },
50 onMessage: {
51 is: ['function', 'undefined']
52 },
53 include: {
54 is: ['string', 'array', 'undefined']
55 },
56 contentScriptWhen: {
57 is: ['string', 'undefined']
58 }
59 }, loaderContract.rules));
61 function enableScript (page) {
62 getDocShell(viewFor(page)).allowJavascript = true;
63 }
65 function disableScript (page) {
66 getDocShell(viewFor(page)).allowJavascript = false;
67 }
69 function Allow (page) {
70 return {
71 get script() { return getDocShell(viewFor(page)).allowJavascript; },
72 set script(value) { return value ? enableScript(page) : disableScript(page); }
73 };
74 }
76 function injectWorker ({page}) {
77 let worker = workerFor(page);
78 let view = viewFor(page);
79 if (isValidURL(page, view.contentDocument.URL))
80 attach(worker, view.contentWindow);
81 }
83 function isValidURL(page, url) !page.rules || page.rules.matchesAny(url)
85 const Page = Class({
86 implements: [
87 EventTarget,
88 Disposable,
89 WeakReference
90 ],
91 extends: WorkerHost(workerFor),
92 setup: function Page(options) {
93 let page = this;
94 options = pageContract(options);
95 let view = makeFrame(window.document, {
96 nodeName: 'iframe',
97 type: 'content',
98 uri: options.contentURL,
99 allowJavascript: options.allow.script,
100 allowPlugins: true,
101 allowAuth: true
102 });
104 ['contentScriptFile', 'contentScript', 'contentScriptWhen']
105 .forEach(prop => page[prop] = options[prop]);
107 views.set(this, view);
108 pages.set(view, this);
110 // Set listeners on the {Page} object itself, not the underlying worker,
111 // like `onMessage`, as it gets piped
112 setListeners(this, options);
113 let worker = new Worker(stripListeners(options));
114 workers.set(this, worker);
115 pipe(worker, this);
117 if (this.include || options.include) {
118 this.rules = Rules();
119 this.rules.add.apply(this.rules, [].concat(this.include || options.include));
120 }
121 },
122 get allow() { return Allow(this); },
123 set allow(value) {
124 let allowJavascript = pageContract({ allow: value }).allow.script;
125 return allowJavascript ? enableScript(this) : disableScript(this);
126 },
127 get contentURL() { return viewFor(this).getAttribute('src'); },
128 set contentURL(value) {
129 if (!isValidURL(this, value)) return;
130 let view = viewFor(this);
131 let contentURL = pageContract({ contentURL: value }).contentURL;
132 view.setAttribute('src', contentURL);
133 },
134 dispose: function () {
135 if (isDisposed(this)) return;
136 let view = viewFor(this);
137 if (view.parentNode) view.parentNode.removeChild(view);
138 views.delete(this);
139 destroy(workers.get(this));
140 },
141 toString: function () { return '[object Page]' }
142 });
144 exports.Page = Page;
146 let pageEvents = streamMerge([events, streamEventsFrom(window)]);
147 let readyEvents = filter(pageEvents, isReadyEvent);
148 let formattedEvents = map(readyEvents, function({target, type}) {
149 return { type: type, page: pageFromDoc(target) };
150 });
151 let pageReadyEvents = filter(formattedEvents, function({page, type}) {
152 return getAttachEventType(page) === type});
153 on(pageReadyEvents, 'data', injectWorker);
155 function isReadyEvent ({type}) {
156 return has(readyEventNames, type);
157 }
159 /*
160 * Takes a document, finds its doc shell tree root and returns the
161 * matching Page instance if found
162 */
163 function pageFromDoc(doc) {
164 let parentWindow = getParentWindow(doc.defaultView), page;
165 if (!parentWindow) return;
167 let frames = parentWindow.document.getElementsByTagName('iframe');
168 for (let i = frames.length; i--;)
169 if (frames[i].contentDocument === doc && (page = pageFor(frames[i])))
170 return page;
171 return null;
172 }