addon-sdk/source/lib/sdk/page-worker.js

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

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 }

mercurial