toolkit/devtools/server/actors/root.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 /* -*- tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
     3 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 "use strict";
     9 let devtools_ = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools;
    10 let { createExtraActors, appendExtraActors } = devtools_.require("devtools/server/actors/common");
    12 /* Root actor for the remote debugging protocol. */
    14 /**
    15  * Create a remote debugging protocol root actor.
    16  *
    17  * @param aConnection
    18  *     The DebuggerServerConnection whose root actor we are constructing.
    19  *
    20  * @param aParameters
    21  *     The properties of |aParameters| provide backing objects for the root
    22  *     actor's requests; if a given property is omitted from |aParameters|, the
    23  *     root actor won't implement the corresponding requests or notifications.
    24  *     Supported properties:
    25  *
    26  *     - tabList: a live list (see below) of tab actors. If present, the
    27  *       new root actor supports the 'listTabs' request, providing the live
    28  *       list's elements as its tab actors, and sending 'tabListChanged'
    29  *       notifications when the live list's contents change. One actor in
    30  *       this list must have a true '.selected' property.
    31  *
    32  *     - addonList: a live list (see below) of addon actors. If present, the
    33  *       new root actor supports the 'listAddons' request, providing the live
    34  *       list's elements as its addon actors, and sending 'addonListchanged'
    35  *       notifications when the live list's contents change.
    36  *
    37  *     - globalActorFactories: an object |A| describing further actors to
    38  *       attach to the 'listTabs' reply. This is the type accumulated by
    39  *       DebuggerServer.addGlobalActor. For each own property |P| of |A|,
    40  *       the root actor adds a property named |P| to the 'listTabs'
    41  *       reply whose value is the name of an actor constructed by
    42  *       |A[P]|.
    43  *
    44  *     - onShutdown: a function to call when the root actor is disconnected.
    45  *
    46  * Instance properties:
    47  *
    48  * - applicationType: the string the root actor will include as the
    49  *      "applicationType" property in the greeting packet. By default, this
    50  *      is "browser".
    51  *
    52  * Live lists:
    53  *
    54  * A "live list", as used for the |tabList|, is an object that presents a
    55  * list of actors, and also notifies its clients of changes to the list. A
    56  * live list's interface is two properties:
    57  *
    58  * - getList: a method that returns a promise to the contents of the list.
    59  *
    60  * - onListChanged: a handler called, with no arguments, when the set of
    61  *             values the iterator would produce has changed since the last
    62  *             time 'iterator' was called. This may only be set to null or a
    63  *             callable value (one for which the typeof operator returns
    64  *             'function'). (Note that the live list will not call the
    65  *             onListChanged handler until the list has been iterated over
    66  *             once; if nobody's seen the list in the first place, nobody
    67  *             should care if its contents have changed!)
    68  *
    69  * When the list changes, the list implementation should ensure that any
    70  * actors yielded in previous iterations whose referents (tabs) still exist
    71  * get yielded again in subsequent iterations. If the underlying referent
    72  * is the same, the same actor should be presented for it.
    73  *
    74  * The root actor registers an 'onListChanged' handler on the appropriate
    75  * list when it may need to send the client 'tabListChanged' notifications,
    76  * and is careful to remove the handler whenever it does not need to send
    77  * such notifications (including when it is disconnected). This means that
    78  * live list implementations can use the state of the handler property (set
    79  * or null) to install and remove observers and event listeners.
    80  *
    81  * Note that, as the only way for the root actor to see the members of the
    82  * live list is to begin an iteration over the list, the live list need not
    83  * actually produce any actors until they are reached in the course of
    84  * iteration: alliterative lazy live lists.
    85  */
    86 function RootActor(aConnection, aParameters) {
    87   this.conn = aConnection;
    88   this._parameters = aParameters;
    89   this._onTabListChanged = this.onTabListChanged.bind(this);
    90   this._onAddonListChanged = this.onAddonListChanged.bind(this);
    91   this._extraActors = {};
    92 }
    94 RootActor.prototype = {
    95   constructor: RootActor,
    96   applicationType: "browser",
    98   /**
    99    * Return a 'hello' packet as specified by the Remote Debugging Protocol.
   100    */
   101   sayHello: function() {
   102     return {
   103       from: this.actorID,
   104       applicationType: this.applicationType,
   105       /* This is not in the spec, but it's used by tests. */
   106       testConnectionPrefix: this.conn.prefix,
   107       traits: {
   108         sources: true,
   109         editOuterHTML: true,
   110         // Wether the server-side highlighter actor exists and can be used to
   111         // remotely highlight nodes (see server/actors/highlighter.js)
   112         highlightable: true,
   113         // Wether the inspector actor implements the getImageDataFromURL
   114         // method that returns data-uris for image URLs. This is used for image
   115         // tooltips for instance
   116         urlToImageDataResolver: true,
   117         networkMonitor: true,
   118         // Wether the storage inspector actor to inspect cookies, etc.
   119         storageInspector: true,
   120         // Wether storage inspector is read only
   121         storageInspectorReadOnly: true,
   122         // Wether conditional breakpoints are supported
   123         conditionalBreakpoints: true
   124       }
   125     };
   126   },
   128   /**
   129    * This is true for the root actor only, used by some child actors
   130    */
   131   get isRootActor() true,
   133   /**
   134    * The (chrome) window, for use by child actors
   135    */
   136   get window() Services.wm.getMostRecentWindow(DebuggerServer.chromeWindowType),
   138   /**
   139    * URL of the chrome window.
   140    */
   141   get url() { return this.window ? this.window.document.location.href : null; },
   143   /**
   144    * Getter for the best nsIWebProgress for to watching this window.
   145    */
   146   get webProgress() {
   147     return this.window
   148       .QueryInterface(Ci.nsIInterfaceRequestor)
   149       .getInterface(Ci.nsIDocShell)
   150       .QueryInterface(Ci.nsIInterfaceRequestor)
   151       .getInterface(Ci.nsIWebProgress);
   152   },
   154   /**
   155    * Disconnects the actor from the browser window.
   156    */
   157   disconnect: function() {
   158     /* Tell the live lists we aren't watching any more. */
   159     if (this._parameters.tabList) {
   160       this._parameters.tabList.onListChanged = null;
   161     }
   162     if (this._parameters.addonList) {
   163       this._parameters.addonList.onListChanged = null;
   164     }
   165     if (typeof this._parameters.onShutdown === 'function') {
   166       this._parameters.onShutdown();
   167     }
   168     this._extraActors = null;
   169   },
   171   /* The 'listTabs' request and the 'tabListChanged' notification. */
   173   /**
   174    * Handles the listTabs request. The actors will survive until at least
   175    * the next listTabs request.
   176    */
   177   onListTabs: function() {
   178     let tabList = this._parameters.tabList;
   179     if (!tabList) {
   180       return { from: this.actorID, error: "noTabs",
   181                message: "This root actor has no browser tabs." };
   182     }
   184     /*
   185      * Walk the tab list, accumulating the array of tab actors for the
   186      * reply, and moving all the actors to a new ActorPool. We'll
   187      * replace the old tab actor pool with the one we build here, thus
   188      * retiring any actors that didn't get listed again, and preparing any
   189      * new actors to receive packets.
   190      */
   191     let newActorPool = new ActorPool(this.conn);
   192     let tabActorList = [];
   193     let selected;
   194     return tabList.getList().then((tabActors) => {
   195       for (let tabActor of tabActors) {
   196         if (tabActor.selected) {
   197           selected = tabActorList.length;
   198         }
   199         tabActor.parentID = this.actorID;
   200         newActorPool.addActor(tabActor);
   201         tabActorList.push(tabActor);
   202       }
   204       /* DebuggerServer.addGlobalActor support: create actors. */
   205       if (!this._globalActorPool) {
   206         this._globalActorPool = new ActorPool(this.conn);
   207         this._createExtraActors(this._parameters.globalActorFactories, this._globalActorPool);
   208         this.conn.addActorPool(this._globalActorPool);
   209       }
   211       /*
   212        * Drop the old actorID -> actor map. Actors that still mattered were
   213        * added to the new map; others will go away.
   214        */
   215       if (this._tabActorPool) {
   216         this.conn.removeActorPool(this._tabActorPool);
   217       }
   218       this._tabActorPool = newActorPool;
   219       this.conn.addActorPool(this._tabActorPool);
   221       let reply = {
   222         "from": this.actorID,
   223         "selected": selected || 0,
   224         "tabs": [actor.form() for (actor of tabActorList)],
   225       };
   227       /* If a root window is accessible, include its URL. */
   228       if (this.url) {
   229         reply.url = this.url;
   230       }
   232       /* DebuggerServer.addGlobalActor support: name actors in 'listTabs' reply. */
   233       this._appendExtraActors(reply);
   235       /*
   236        * Now that we're actually going to report the contents of tabList to
   237        * the client, we're responsible for letting the client know if it
   238        * changes.
   239        */
   240       tabList.onListChanged = this._onTabListChanged;
   242       return reply;
   243     });
   244   },
   246   onTabListChanged: function () {
   247     this.conn.send({ from: this.actorID, type:"tabListChanged" });
   248     /* It's a one-shot notification; no need to watch any more. */
   249     this._parameters.tabList.onListChanged = null;
   250   },
   252   onListAddons: function () {
   253     let addonList = this._parameters.addonList;
   254     if (!addonList) {
   255       return { from: this.actorID, error: "noAddons",
   256                message: "This root actor has no browser addons." };
   257     }
   259     return addonList.getList().then((addonActors) => {
   260       let addonActorPool = new ActorPool(this.conn);
   261       for (let addonActor of addonActors) {
   262           addonActorPool.addActor(addonActor);
   263       }
   265       if (this._addonActorPool) {
   266         this.conn.removeActorPool(this._addonActorPool);
   267       }
   268       this._addonActorPool = addonActorPool;
   269       this.conn.addActorPool(this._addonActorPool);
   271       addonList.onListChanged = this._onAddonListChanged;
   273       return {
   274         "from": this.actorID,
   275         "addons": [addonActor.form() for (addonActor of addonActors)]
   276       };
   277     });
   278   },
   280   onAddonListChanged: function () {
   281     this.conn.send({ from: this.actorID, type: "addonListChanged" });
   282     this._parameters.addonList.onListChanged = null;
   283   },
   285   /* This is not in the spec, but it's used by tests. */
   286   onEcho: function (aRequest) {
   287     /*
   288      * Request packets are frozen. Copy aRequest, so that
   289      * DebuggerServerConnection.onPacket can attach a 'from' property.
   290      */
   291     return JSON.parse(JSON.stringify(aRequest));
   292   },
   294   onProtocolDescription: function (aRequest) {
   295     return protocol.dumpProtocolSpec()
   296   },
   298   /* Support for DebuggerServer.addGlobalActor. */
   299   _createExtraActors: createExtraActors,
   300   _appendExtraActors: appendExtraActors,
   302   /* ThreadActor hooks. */
   304   /**
   305    * Prepare to enter a nested event loop by disabling debuggee events.
   306    */
   307   preNest: function() {
   308     // Disable events in all open windows.
   309     let e = Services.wm.getEnumerator(null);
   310     while (e.hasMoreElements()) {
   311       let win = e.getNext();
   312       let windowUtils = win.QueryInterface(Ci.nsIInterfaceRequestor)
   313                            .getInterface(Ci.nsIDOMWindowUtils);
   314       windowUtils.suppressEventHandling(true);
   315       windowUtils.suspendTimeouts();
   316     }
   317   },
   319   /**
   320    * Prepare to exit a nested event loop by enabling debuggee events.
   321    */
   322   postNest: function(aNestData) {
   323     // Enable events in all open windows.
   324     let e = Services.wm.getEnumerator(null);
   325     while (e.hasMoreElements()) {
   326       let win = e.getNext();
   327       let windowUtils = win.QueryInterface(Ci.nsIInterfaceRequestor)
   328                            .getInterface(Ci.nsIDOMWindowUtils);
   329       windowUtils.resumeTimeouts();
   330       windowUtils.suppressEventHandling(false);
   331     }
   332   }
   333 };
   335 RootActor.prototype.requestTypes = {
   336   "listTabs": RootActor.prototype.onListTabs,
   337   "listAddons": RootActor.prototype.onListAddons,
   338   "echo": RootActor.prototype.onEcho,
   339   "protocolDescription": RootActor.prototype.onProtocolDescription
   340 };

mercurial