Bug 1249224 - window.open() should open a new window in the same container, r=bz
☠☠ backed out by 487c401fb823 ☠ ☠
authorAndrea Marchesini <amarchesini@mozilla.com>
Mon, 07 Mar 2016 16:22:12 +0100
changeset 324970 05cef11d91beeb0a2f270497ec1a4ee409972db1
parent 324969 8b653b2c71f53c25e84ed10f1117a46f12280b19
child 324971 3861ebac90e69ca083c577a4623800521a655402
push id6048
push userkmoir@mozilla.com
push dateMon, 06 Jun 2016 19:02:08 +0000
treeherdermozilla-beta@46d72a56c57d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs1249224
milestone47.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 1249224 - window.open() should open a new window in the same container, r=bz
embedding/components/windowwatcher/moz.build
embedding/components/windowwatcher/nsWindowWatcher.cpp
--- a/embedding/components/windowwatcher/moz.build
+++ b/embedding/components/windowwatcher/moz.build
@@ -32,10 +32,11 @@ EXPORTS += [
 if CONFIG['MOZ_XUL']:
     UNIFIED_SOURCES += [
         'nsDialogParamBlock.cpp',
     ]
 
 FINAL_LIBRARY = 'xul'
 # For nsJSUtils
 LOCAL_INCLUDES += [
+    '/docshell/base',
     '/dom/base',
 ]
--- a/embedding/components/windowwatcher/nsWindowWatcher.cpp
+++ b/embedding/components/windowwatcher/nsWindowWatcher.cpp
@@ -13,16 +13,17 @@
 #include "nsNetUtil.h"
 #include "nsIAuthPrompt.h"
 #include "nsIAuthPrompt2.h"
 #include "nsISimpleEnumerator.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsJSUtils.h"
 #include "plstr.h"
 
+#include "nsDocShell.h"
 #include "nsIBaseWindow.h"
 #include "nsIBrowserDOMWindow.h"
 #include "nsIDocShell.h"
 #include "nsIDocShellLoadInfo.h"
 #include "nsIDocShellTreeItem.h"
 #include "nsIDocShellTreeOwner.h"
 #include "nsIDocumentLoader.h"
 #include "nsIDocument.h"
@@ -442,16 +443,46 @@ nsWindowWatcher::OpenWindow2(mozIDOMWind
     dialog = argc > 0;
   }
 
   return OpenWindowInternal(aParent, aUrl, aName, aFeatures,
                             aCalledFromScript, dialog,
                             aNavigate, aOpeningTab, argv, aResult);
 }
 
+// This static function checks if the aDocShell uses an UserContextId equal to
+// nsIScriptSecurityManager::DEFAULT_USER_CONTEXT_ID or equal to the
+// userContextId of subjectPrincipal, if not null.
+static bool
+CheckUserContextCompatibility(nsIDocShell* aDocShell)
+{
+  MOZ_ASSERT(aDocShell);
+
+  uint32_t userContextId =
+    static_cast<nsDocShell*>(aDocShell)->GetOriginAttributes().mUserContextId;
+
+  if (userContextId == nsIScriptSecurityManager::DEFAULT_USER_CONTEXT_ID) {
+    return true;
+  }
+
+  nsCOMPtr<nsIPrincipal> subjectPrincipal =
+    nsContentUtils::GetCurrentJSContext()
+      ? nsContentUtils::SubjectPrincipal() : nullptr;
+
+  if (!subjectPrincipal) {
+    return false;
+  }
+
+  uint32_t principalUserContextId;
+  nsresult rv = subjectPrincipal->GetUserContextId(&principalUserContextId);
+  NS_ENSURE_SUCCESS(rv, false);
+
+  return principalUserContextId == userContextId;
+}
+
 nsresult
 nsWindowWatcher::OpenWindowInternal(mozIDOMWindowProxy* aParent,
                                     const char* aUrl,
                                     const char* aName,
                                     const char* aFeatures,
                                     bool aCalledFromJS,
                                     bool aDialog,
                                     bool aNavigate,
@@ -676,16 +707,29 @@ nsWindowWatcher::OpenWindowInternal(mozI
             // Make sure to stop any loads happening in this window that the
             // window provider might have started.  Otherwise if our caller
             // manipulates the window it just opened and then the load
             // completes their stuff will get blown away.
             nsCOMPtr<nsIWebNavigation> webNav =
               do_QueryInterface(newDocShellItem);
             webNav->Stop(nsIWebNavigation::STOP_NETWORK);
           }
+
+          // If this is a new window, but it's incompatible with the current
+          // userContextId, we ignore it and we pretend that nothing has been
+          // returned by ProvideWindow.
+          if (!windowIsNew && newDocShellItem) {
+            nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(newDocShellItem);
+            if (!CheckUserContextCompatibility(docShell)) {
+              newWindow = nullptr;
+              newDocShellItem = nullptr;
+              windowIsNew = false;
+            }
+          }
+
         } else if (rv == NS_ERROR_ABORT) {
           // NS_ERROR_ABORT means the window provider has flat-out rejected
           // the open-window call and we should bail.  Don't return an error
           // here, because our caller may propagate that error, which might
           // cause e.g. window.open to throw!  Just return null for our out
           // param.
           return NS_OK;
         }
@@ -964,26 +1008,41 @@ nsWindowWatcher::OpenWindowInternal(mozI
     }
     if (doc) {
       // Set the referrer
       loadInfo->SetReferrer(doc->GetDocumentURI());
       loadInfo->SetReferrerPolicy(doc->GetReferrerPolicy());
     }
   }
 
+  // If this is a new window, we must set the userContextId from the
+  // subjectPrincipal.
+  if (windowIsNew && subjectPrincipal) {
+    uint32_t userContextId;
+    rv = subjectPrincipal->GetUserContextId(&userContextId);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    rv = newDocShell->SetUserContextId(userContextId);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
   if (isNewToplevelWindow) {
     // Notify observers that the window is open and ready.
     // The window has not yet started to load a document.
     nsCOMPtr<nsIObserverService> obsSvc =
       mozilla::services::GetObserverService();
     if (obsSvc) {
       obsSvc->NotifyObservers(*aResult, "toplevel-window-ready", nullptr);
     }
   }
 
+  // Before loading the URI we want to be 100% sure that we use the correct
+  // userContextId.
+  MOZ_ASSERT(CheckUserContextCompatibility(newDocShell));
+
   if (uriToLoad && aNavigate) {
     newDocShell->LoadURI(
       uriToLoad,
       loadInfo,
       windowIsNew ?
         static_cast<uint32_t>(nsIWebNavigation::LOAD_FLAGS_FIRST_LOAD) :
         static_cast<uint32_t>(nsIWebNavigation::LOAD_FLAGS_NONE),
       true);