Bug 1531163 - Add support for 'allFrames' and 'includeChrome' to JS Window Actors, r=jdai
authorNika Layzell <nika@thelayzells.com>
Fri, 01 Mar 2019 17:25:44 +0000
changeset 520265 307b8e123debf65f7cbe58dcee28ef871747fbae
parent 520264 ae274634278fa08c629d11b98d1c14bf2baf70ee
child 520266 8ff9537201ef4849f867d490a8686fa408ce24fd
push id10862
push userffxbld-merge
push dateMon, 11 Mar 2019 13:01:11 +0000
treeherdermozilla-beta@a2e7f5c935da [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjdai
bugs1531163
milestone67.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1531163 - Add support for 'allFrames' and 'includeChrome' to JS Window Actors, r=jdai Differential Revision: https://phabricator.services.mozilla.com/D21453
dom/chrome-webidl/ChromeUtils.webidl
dom/ipc/JSWindowActorService.cpp
dom/ipc/JSWindowActorService.h
dom/ipc/PContent.ipdl
dom/ipc/WindowGlobalChild.cpp
dom/ipc/WindowGlobalParent.cpp
dom/ipc/tests/test_JSWindowActor.xul
--- a/dom/chrome-webidl/ChromeUtils.webidl
+++ b/dom/chrome-webidl/ChromeUtils.webidl
@@ -588,16 +588,29 @@ dictionary HeapSnapshotBoundaries {
 };
 
 dictionary Base64URLEncodeOptions {
   /** Specifies whether the output should be padded with "=" characters. */
   required boolean pad;
 };
 
 dictionary WindowActorOptions {
+  /**
+   * If this is set to `true`, allow this actor to be created for subframes,
+   * and not just toplevel window globals.
+   */
+  boolean allFrames = false;
+
+  /**
+   * If this is set to `true`, allow this actor to be created for window
+   * globals loaded in chrome browsing contexts, such as those used to load the
+   * tabbrowser.
+   */
+  boolean includeChrome = false;
+
   /** This fields are used for configuring individual sides of the actor. */
   required WindowActorSidedOptions parent;
   required WindowActorChildOptions child;
 };
 
 dictionary WindowActorSidedOptions {
   /** The module path which should be loaded for the actor on this side. */
   required ByteString moduleURI;
--- a/dom/ipc/JSWindowActorService.cpp
+++ b/dom/ipc/JSWindowActorService.cpp
@@ -115,41 +115,49 @@ class JSWindowActorProtocol final : publ
   };
 
   struct ChildSide : public Sided {
     nsTArray<EventDecl> mEvents;
     nsTArray<nsCString> mObservers;
   };
 
   const nsAString& Name() const { return mName; }
+  bool AllFrames() const { return mAllFrames; }
+  bool IncludeChrome() const { return mIncludeChrome; }
   const ParentSide& Parent() const { return mParent; }
   const ChildSide& Child() const { return mChild; }
 
   void RegisterListenersFor(EventTarget* aRoot);
   void UnregisterListenersFor(EventTarget* aRoot);
   void AddObservers();
   void RemoveObservers();
 
  private:
   explicit JSWindowActorProtocol(const nsAString& aName) : mName(aName) {}
 
   ~JSWindowActorProtocol() = default;
 
   nsString mName;
+  bool mAllFrames = false;
+  bool mIncludeChrome = false;
   ParentSide mParent;
   ChildSide mChild;
 };
 
 NS_IMPL_ISUPPORTS(JSWindowActorProtocol, nsIObserver, nsIDOMEventListener);
 
 /* static */ already_AddRefed<JSWindowActorProtocol>
 JSWindowActorProtocol::FromIPC(const JSWindowActorInfo& aInfo) {
   MOZ_DIAGNOSTIC_ASSERT(XRE_IsContentProcess());
 
   RefPtr<JSWindowActorProtocol> proto = new JSWindowActorProtocol(aInfo.name());
+  // Content processes cannot load chrome browsing contexts, so this flag is
+  // irrelevant and not propagated.
+  proto->mIncludeChrome = false;
+  proto->mAllFrames = aInfo.allFrames();
   proto->mChild.mModuleURI.Assign(aInfo.url());
 
   proto->mChild.mEvents.SetCapacity(aInfo.events().Length());
   for (auto& ipc : aInfo.events()) {
     auto* event = proto->mChild.mEvents.AppendElement();
     event->mName.Assign(ipc.name());
     event->mFlags.mCapture = ipc.capture();
     event->mFlags.mInSystemGroup = ipc.systemGroup();
@@ -163,16 +171,17 @@ JSWindowActorProtocol::FromIPC(const JSW
   return proto.forget();
 }
 
 JSWindowActorInfo JSWindowActorProtocol::ToIPC() {
   MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess());
 
   JSWindowActorInfo info;
   info.name() = mName;
+  info.allFrames() = mAllFrames;
   info.url() = mChild.mModuleURI;
 
   info.events().SetCapacity(mChild.mEvents.Length());
   for (auto& event : mChild.mEvents) {
     auto* ipc = info.events().AppendElement();
     ipc->name().Assign(event.mName);
     ipc->capture() = event.mFlags.mCapture;
     ipc->systemGroup() = event.mFlags.mInSystemGroup;
@@ -189,16 +198,18 @@ JSWindowActorInfo JSWindowActorProtocol:
 
 already_AddRefed<JSWindowActorProtocol>
 JSWindowActorProtocol::FromWebIDLOptions(const nsAString& aName,
                                          const WindowActorOptions& aOptions,
                                          ErrorResult& aRv) {
   MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess());
 
   RefPtr<JSWindowActorProtocol> proto = new JSWindowActorProtocol(aName);
+  proto->mAllFrames = aOptions.mAllFrames;
+
   proto->mParent.mModuleURI = aOptions.mParent.mModuleURI;
   proto->mChild.mModuleURI = aOptions.mChild.mModuleURI;
 
   // For each event declared in the source dictionary, initialize the
   // corresponding envent declaration entry in the JSWindowActorProtocol.
   if (aOptions.mChild.mEvents.WasPassed()) {
     auto& entries = aOptions.mChild.mEvents.Value().Entries();
     proto->mChild.mEvents.SetCapacity(entries.Length());
@@ -254,18 +265,24 @@ NS_IMETHODIMP JSWindowActorProtocol::Han
   RefPtr<WindowGlobalChild> wgc = inner->GetWindowGlobalChild();
   if (NS_WARN_IF(!wgc)) {
     return NS_ERROR_FAILURE;
   }
 
   // Ensure our actor is present.
   ErrorResult error;
   RefPtr<JSWindowActorChild> actor = wgc->GetActor(mName, error);
-  if (NS_WARN_IF(error.Failed())) {
-    return error.StealNSResult();
+  if (error.Failed()) {
+    nsresult rv = error.StealNSResult();
+
+    // Don't raise an error if creation of our actor was vetoed.
+    if (rv == NS_ERROR_NOT_AVAILABLE) {
+      return NS_OK;
+    }
+    return rv;
   }
 
   // Call the "handleEvent" method on our actor.
   JS::Rooted<JS::Value> dummy(RootingCx());
   return CallJSActorMethod(actor, "handleEvent", aEvent, &dummy);
 }
 
 NS_IMETHODIMP JSWindowActorProtocol::Observe(nsISupports* aSubject,
@@ -469,16 +486,17 @@ void JSWindowActorService::GetJSWindowAc
 
   for (auto iter = mDescriptors.ConstIter(); !iter.Done(); iter.Next()) {
     aInfos.AppendElement(iter.Data()->ToIPC());
   }
 }
 
 void JSWindowActorService::ConstructActor(const nsAString& aName,
                                           bool aParentSide,
+                                          BrowsingContext* aBrowsingContext,
                                           JS::MutableHandleObject aActor,
                                           ErrorResult& aRv) {
   MOZ_ASSERT_IF(aParentSide, XRE_IsParentProcess());
 
   // Constructing an actor requires a running script, so push an AutoEntryScript
   // onto the stack.
   AutoEntryScript aes(xpc::PrivilegedJunkScope(), "JSWindowActor construction");
   JSContext* cx = aes.cx();
@@ -492,16 +510,28 @@ void JSWindowActorService::ConstructActo
 
   const JSWindowActorProtocol::Sided* side;
   if (aParentSide) {
     side = &proto->Parent();
   } else {
     side = &proto->Child();
   }
 
+  // Check if our current BrowsingContext matches the requirements for this
+  // actor to load.
+  if (!proto->AllFrames() && aBrowsingContext->GetParent()) {
+    aRv.Throw(NS_ERROR_NOT_AVAILABLE);
+    return;
+  }
+
+  if (!proto->IncludeChrome() && !aBrowsingContext->IsContent()) {
+    aRv.Throw(NS_ERROR_NOT_AVAILABLE);
+    return;
+  }
+
   // Load the module using mozJSComponentLoader.
   RefPtr<mozJSComponentLoader> loader = mozJSComponentLoader::Get();
   MOZ_ASSERT(loader);
 
   JS::RootedObject global(cx);
   JS::RootedObject exports(cx);
   aRv = loader->Import(cx, side->mModuleURI, &global, &exports);
   if (aRv.Failed()) {
--- a/dom/ipc/JSWindowActorService.h
+++ b/dom/ipc/JSWindowActorService.h
@@ -35,16 +35,17 @@ class JSWindowActorService final {
   // Get the named of Window Actor and the child's WindowActorOptions
   // from mDescriptors to JSWindowActorInfos.
   void GetJSWindowActorInfos(nsTArray<JSWindowActorInfo>& aInfos);
 
   // Load the module for the named Window Actor and contruct it.
   // This method will not initialize the actor or set its manager,
   // which is handled by callers.
   void ConstructActor(const nsAString& aName, bool aParentSide,
+                      BrowsingContext* aBrowsingContext,
                       JS::MutableHandleObject aActor, ErrorResult& aRv);
 
   void ReceiveMessage(JS::RootedObject& aObj, const nsString& aMessageName,
                       ipc::StructuredCloneData& aData);
 
   // Register or unregister a WindowRoot object from this JSWindowActorService.
   void RegisterWindowRoot(EventTarget* aRoot);
 
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -235,16 +235,17 @@ struct JSWindowActorEventDecl
   // encoded as two booleans.
   bool hasPassive;
   bool passive;
 };
 
 struct JSWindowActorInfo
 {
   nsString name;
+  bool allFrames;
   nsCString url;
 
   JSWindowActorEventDecl[] events;
   nsCString[] observers;
 };
 
 struct GMPAPITags
 {
--- a/dom/ipc/WindowGlobalChild.cpp
+++ b/dom/ipc/WindowGlobalChild.cpp
@@ -161,17 +161,18 @@ already_AddRefed<JSWindowActorChild> Win
   // Otherwise, we want to create a new instance of this actor. Call into the
   // JSWindowActorService to trigger construction.
   RefPtr<JSWindowActorService> actorSvc = JSWindowActorService::GetSingleton();
   if (!actorSvc) {
     return nullptr;
   }
 
   JS::RootedObject obj(RootingCx());
-  actorSvc->ConstructActor(aName, /* aChildSide */ false, &obj, aRv);
+  actorSvc->ConstructActor(aName, /* aChildSide */ false, mBrowsingContext,
+                           &obj, aRv);
   if (aRv.Failed()) {
     return nullptr;
   }
 
   // Unwrap our actor to a JSWindowActorChild object.
   RefPtr<JSWindowActorChild> actor;
   if (NS_FAILED(UNWRAP_OBJECT(JSWindowActorChild, &obj, actor))) {
     return nullptr;
--- a/dom/ipc/WindowGlobalParent.cpp
+++ b/dom/ipc/WindowGlobalParent.cpp
@@ -204,17 +204,18 @@ already_AddRefed<JSWindowActorParent> Wi
   // Otherwise, we want to create a new instance of this actor. Call into the
   // JSWindowActorService to trigger construction
   RefPtr<JSWindowActorService> actorSvc = JSWindowActorService::GetSingleton();
   if (!actorSvc) {
     return nullptr;
   }
 
   JS::RootedObject obj(RootingCx());
-  actorSvc->ConstructActor(aName, /* aParentSide */ true, &obj, aRv);
+  actorSvc->ConstructActor(aName, /* aParentSide */ true, mBrowsingContext,
+                           &obj, aRv);
   if (aRv.Failed()) {
     return nullptr;
   }
 
   // Unwrap our actor to a JSWindowActorParent object.
   RefPtr<JSWindowActorParent> actor;
   if (NS_FAILED(UNWRAP_OBJECT(JSWindowActorParent, &obj, actor))) {
     return nullptr;
--- a/dom/ipc/tests/test_JSWindowActor.xul
+++ b/dom/ipc/tests/test_JSWindowActor.xul
@@ -13,16 +13,17 @@
   <body xmlns="http://www.w3.org/1999/xhtml">
   </body>
 
   <!-- test code goes here -->
   <script type="application/javascript"><![CDATA[
   const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
   const URL = "about:blank";
   let windowActorOptions = {
+    allFrames: true,
     parent: {
       moduleURI: "resource://testing-common/TestParent.jsm",
     },
     child: {
       moduleURI: "resource://testing-common/TestChild.jsm",
       observers: [
         "test-js-window-actor-child-observer",
       ],