Bug 1502328 - Add opener member to BrowsingContext and expose through webidl. r=nika
authorAndreas Farre <farre@mozilla.com>
Fri, 09 Nov 2018 08:53:53 +0000
changeset 445384 d697bd75684dbefca9f156d90446523cdaa82f22
parent 445383 157be32d85fe86d9a091381ce7e304c834df4ce1
child 445385 587532e4c6fee04681c12d552ee7013c4896d278
push id35015
push userdluca@mozilla.com
push dateFri, 09 Nov 2018 17:45:20 +0000
treeherdermozilla-central@2f1158e5e0ce [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnika
bugs1502328
milestone65.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 1502328 - Add opener member to BrowsingContext and expose through webidl. r=nika Differential Revision: https://phabricator.services.mozilla.com/D10580
docshell/base/BrowsingContext.cpp
docshell/base/BrowsingContext.h
dom/base/nsGlobalWindowOuter.cpp
dom/base/nsPIDOMWindow.h
dom/chrome-webidl/BrowsingContext.webidl
dom/ipc/ContentParent.cpp
dom/ipc/ContentParent.h
dom/ipc/PContent.ipdl
--- a/docshell/base/BrowsingContext.cpp
+++ b/docshell/base/BrowsingContext.cpp
@@ -279,16 +279,35 @@ BrowsingContext::IsCached()
 void
 BrowsingContext::GetChildren(nsTArray<RefPtr<BrowsingContext>>& aChildren)
 {
   for (BrowsingContext* context : mChildren) {
     aChildren.AppendElement(context);
   }
 }
 
+void
+BrowsingContext::SetOpener(BrowsingContext* aOpener)
+{
+  if (mOpener == aOpener) {
+    return;
+  }
+
+  mOpener = aOpener;
+
+  if (!XRE_IsContentProcess()) {
+    return;
+  }
+
+  auto cc = ContentChild::GetSingleton();
+  MOZ_DIAGNOSTIC_ASSERT(cc);
+  cc->SendSetOpenerBrowsingContext(BrowsingContextId(Id()),
+                                   BrowsingContextId(aOpener ? aOpener->Id() : 0));
+}
+
 /* static */ void
 BrowsingContext::GetRootBrowsingContexts(nsTArray<RefPtr<BrowsingContext>>& aBrowsingContexts)
 {
   for (BrowsingContext* context : *sRootBrowsingContexts) {
     aBrowsingContexts.AppendElement(context);
   }
 }
 
--- a/docshell/base/BrowsingContext.h
+++ b/docshell/base/BrowsingContext.h
@@ -106,16 +106,23 @@ public:
   bool IsContent() const { return mType == Type::Content; }
 
   uint64_t Id() const { return mBrowsingContextId; }
 
   BrowsingContext* GetParent() { return mParent; }
 
   void GetChildren(nsTArray<RefPtr<BrowsingContext>>& aChildren);
 
+  BrowsingContext* GetOpener()
+  {
+    return mOpener;
+  }
+
+  void SetOpener(BrowsingContext* aOpener);
+
   static void GetRootBrowsingContexts(
     nsTArray<RefPtr<BrowsingContext>>& aBrowsingContexts);
 
   nsISupports* GetParentObject() const;
   virtual JSObject* WrapObject(JSContext* aCx,
                                JS::Handle<JSObject*> aGivenProto) override;
 
   MOZ_DECLARE_WEAKREFERENCE_TYPENAME(BrowsingContext)
@@ -136,15 +143,16 @@ private:
   const Type mType;
 
   // Unique id identifying BrowsingContext
   const uint64_t mBrowsingContextId;
 
 
   WeakPtr<BrowsingContext> mParent;
   Children mChildren;
+  WeakPtr<BrowsingContext> mOpener;
   nsCOMPtr<nsIDocShell> mDocShell;
   nsString mName;
 };
 
 } // namespace dom
 } // namespace mozilla
 #endif
--- a/dom/base/nsGlobalWindowOuter.cpp
+++ b/dom/base/nsGlobalWindowOuter.cpp
@@ -2238,28 +2238,38 @@ nsGlobalWindowOuter::DetachFromDocShell(
 }
 
 void
 nsGlobalWindowOuter::SetOpenerWindow(nsPIDOMWindowOuter* aOpener,
                                      bool aOriginalOpener)
 {
   nsWeakPtr opener = do_GetWeakReference(aOpener);
   if (opener == mOpener) {
+    MOZ_DIAGNOSTIC_ASSERT(
+      !aOpener || (GetBrowsingContext() && GetBrowsingContext()->GetOpener() ==
+                                             aOpener->GetBrowsingContext()));
     return;
   }
 
   NS_ASSERTION(!aOriginalOpener || !mSetOpenerWindowCalled,
                "aOriginalOpener is true, but not first call to "
                "SetOpenerWindow!");
   NS_ASSERTION(aOpener || !aOriginalOpener,
                "Shouldn't set mHadOriginalOpener if aOpener is null");
 
   mOpener = opener.forget();
   NS_ASSERTION(mOpener || !aOpener, "Opener must support weak references!");
 
+  if (mDocShell && aOpener) {
+    // TODO(farre): Here we really wish to only consider the case
+    // where 'aOriginalOpener' is false, and we also really want to
+    // move opener entirely to BrowsingContext. See bug 1502330.
+    GetBrowsingContext()->SetOpener(aOpener->GetBrowsingContext());
+  }
+
   // Check that the js visible opener matches! We currently don't depend on this
   // being true outside of nightly, so we disable the assertion in optimized
   // release / beta builds.
   nsPIDOMWindowOuter* contentOpener = GetSanitizedOpener(aOpener);
 
   // contentOpener is not used when the DIAGNOSTIC_ASSERT is compiled out.
   mozilla::Unused << contentOpener;
   MOZ_DIAGNOSTIC_ASSERT(!contentOpener || !mTabGroup ||
@@ -7863,8 +7873,14 @@ nsAutoPopupStatePusherInternal::nsAutoPo
   : mOldState(nsContentUtils::PushPopupControlState(aState, aForce))
 {
 }
 
 nsAutoPopupStatePusherInternal::~nsAutoPopupStatePusherInternal()
 {
   nsContentUtils::PopPopupControlState(mOldState);
 }
+
+mozilla::dom::BrowsingContext*
+nsPIDOMWindowOuter::GetBrowsingContext() const
+{
+  return mDocShell ? nsDocShell::Cast(mDocShell)->GetBrowsingContext() : nullptr;
+}
--- a/dom/base/nsPIDOMWindow.h
+++ b/dom/base/nsPIDOMWindow.h
@@ -43,16 +43,17 @@ class nsPIWindowRoot;
 class nsXBLPrototypeHandler;
 
 typedef uint32_t SuspendTypes;
 
 namespace mozilla {
 class AutoplayPermissionManager;
 namespace dom {
 class AudioContext;
+class BrowsingContext;
 class ClientInfo;
 class ClientState;
 class ContentFrameMessageManager;
 class DocGroup;
 class TabGroup;
 class Element;
 class MozIdleObserver;
 class Navigator;
@@ -924,16 +925,18 @@ public:
   // the window was frozen.
   virtual nsresult FireDelayedDOMEvents() = 0;
 
   /**
    * Get the docshell in this window.
    */
   inline nsIDocShell *GetDocShell() const;
 
+  mozilla::dom::BrowsingContext* GetBrowsingContext() const;
+
   /**
    * Set a new document in the window. Calling this method will in most cases
    * create a new inner window. This may be called with a pointer to the current
    * document, in that case the document remains unchanged, but a new inner
    * window will be created.
    *
    * aDocument must not be null.
    */
--- a/dom/chrome-webidl/BrowsingContext.webidl
+++ b/dom/chrome-webidl/BrowsingContext.webidl
@@ -9,9 +9,11 @@ interface nsIDocShell;
 interface BrowsingContext {
   readonly attribute BrowsingContext? parent;
 
   sequence<BrowsingContext> getChildren();
 
   readonly attribute nsIDocShell? docShell;
 
   readonly attribute unsigned long long id;
+
+  readonly attribute BrowsingContext? opener;
 };
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -6093,8 +6093,44 @@ ContentParent::RecvDetachBrowsingContext
   if (aMoveToBFCache) {
     context->CacheChildren();
   } else {
     context->Detach();
   }
 
   return IPC_OK();
 }
+
+mozilla::ipc::IPCResult
+ContentParent::RecvSetOpenerBrowsingContext(
+  const BrowsingContextId& aContextId,
+  const BrowsingContextId& aOpenerContextId)
+{
+  RefPtr<ChromeBrowsingContext> context = ChromeBrowsingContext::Get(aContextId);
+
+  if (!context) {
+    MOZ_LOG(BrowsingContext::GetLog(),
+            LogLevel::Debug,
+            ("ParentIPC: Trying to set opener already detached 0x%08" PRIx64,
+             (uint64_t)aContextId));
+    return IPC_OK();
+  }
+
+  if (!context->IsOwnedByProcess(ChildID())) {
+    // Where trying to set opener on a child BrowsingContext in
+    // another child process. This is illegal since the owner of the
+    // BrowsingContext is the proccess with the in-process docshell,
+    // which is tracked by OwnerProcessId.
+
+    // TODO(farre): To crash or not to crash. Same reasoning as in
+    // above TODO. [Bug 1471598]
+    MOZ_LOG(BrowsingContext::GetLog(),
+            LogLevel::Warning,
+            ("ParentIPC: Trying to set opener on out of process context 0x%08" PRIx64,
+             context->Id()));
+    return IPC_OK();
+  }
+
+  RefPtr<BrowsingContext> opener = BrowsingContext::Get(aOpenerContextId);
+  context->SetOpener(opener);
+
+  return IPC_OK();
+}
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -680,16 +680,20 @@ public:
     const BrowsingContextId& aParentContextId,
     const BrowsingContextId& aContextId,
     const nsString& aName) override;
 
   virtual mozilla::ipc::IPCResult RecvDetachBrowsingContext(
     const BrowsingContextId& aContextId,
     const bool& aMoveToBFCache) override;
 
+  virtual mozilla::ipc::IPCResult RecvSetOpenerBrowsingContext(
+    const BrowsingContextId& aContextId,
+    const BrowsingContextId& aOpenerContextId) override;
+
 protected:
   void OnChannelConnected(int32_t pid) override;
 
   virtual void ActorDestroy(ActorDestroyReason why) override;
 
   bool ShouldContinueFromReplyTimeout() override;
 
   void OnVarChanged(const GfxVarUpdate& aVar) override;
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -1185,16 +1185,24 @@ parent:
      * an error to call DetachBrowsingContext on a BrowsingContext
      * belonging to an already detached subtree. The 'aMoveToBFCache'
      * paramater controls if detaching a BrowsingContext should move
      * it to the bfcache allowing it to be re-attached if navigated
      * to.
      */
     async DetachBrowsingContext(BrowsingContextId aContextId,
                                 bool aMoveToBFCache);
+
+    /**
+     * Set the opener of browsing context with id 'aContextId' to the
+     * browsing context with id 'aOpenerId'.
+     */
+    async SetOpenerBrowsingContext(BrowsingContextId aContextId,
+                                   BrowsingContextId aOpenerContextId);
+
 both:
      async AsyncMessage(nsString aMessage, CpowEntry[] aCpows,
                         Principal aPrincipal, ClonedMessageData aData);
 
     /**
      * Notify `push-subscription-modified` observers in the parent and child.
      */
     async NotifyPushSubscriptionModifiedObservers(nsCString scope,