Bug 522351 - check for remote="true" on the element before trying to remote it, r=bz
authorBenjamin Smedberg <benjamin@smedbergs.us>
Fri, 16 Oct 2009 15:42:27 -0400
changeset 36008 80adc4f2bad012252c173b92f4494b0d544beeca
parent 36007 fa24fd472835e474f3066cfca2faece350195ecf
child 36009 878b8862b695926c1bf137afde7ef013bc4d14c9
push idunknown
push userunknown
push dateunknown
reviewersbz
bugs522351
milestone1.9.3a1pre
Bug 522351 - check for remote="true" on the element before trying to remote it, r=bz
content/base/src/nsFrameLoader.cpp
content/base/src/nsFrameLoader.h
content/base/src/nsGkAtomList.h
dom/ipc/test.xul
--- a/content/base/src/nsFrameLoader.cpp
+++ b/content/base/src/nsFrameLoader.cpp
@@ -219,34 +219,43 @@ nsFrameLoader::LoadURI(nsIURI* aURI)
   return rv;
 }
 
 nsresult
 nsFrameLoader::ReallyStartLoading()
 {
   NS_ENSURE_STATE(mURIToLoad && mOwnerContent && mOwnerContent->IsInDoc());
 
-#ifdef MOZ_IPC
-  if (!mTriedNewProcess) {
-    TryNewProcess();
-    mTriedNewProcess = PR_TRUE;
+  nsresult rv = MaybeCreateDocShell();
+  if (NS_FAILED(rv)) {
+    return rv;
   }
 
-  if (mChildProcess) {
+#ifdef MOZ_IPC
+  if (mRemoteFrame) {
+    if (!mChildProcess) {
+      TryNewProcess();
+    }
+
+    if (!mChildProcess) {
+      NS_WARNING("Couldn't create child process for iframe.");
+      return NS_ERROR_FAILURE;
+    }
+
     // FIXME get error codes from child
     mChildProcess->LoadURL(mURIToLoad);
     return NS_OK;
   }
 #endif
-  
+
+  NS_ASSERTION(mDocShell,
+               "MaybeCreateDocShell succeeded with a null mDocShell");
+
   // Just to be safe, recheck uri.
-  nsresult rv = CheckURILoad(mURIToLoad);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = EnsureDocShell();
+  rv = CheckURILoad(mURIToLoad);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
   mDocShell->CreateLoadInfo(getter_AddRefs(loadInfo));
   NS_ENSURE_TRUE(loadInfo, NS_ERROR_FAILURE);
 
   // We'll use our principal, not that of the document loaded inside us.  This
   // is very important; needed to prevent XSS attacks on documents loaded in
@@ -300,30 +309,44 @@ nsFrameLoader::CheckURILoad(nsIURI* aURI
   nsresult rv =
     secMan->CheckLoadURIWithPrincipal(principal, aURI,
                                       nsIScriptSecurityManager::STANDARD);
   if (NS_FAILED(rv)) {
     return rv; // We're not
   }
 
   // Bail out if this is an infinite recursion scenario
+  rv = MaybeCreateDocShell();
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  if (mRemoteFrame) {
+    return NS_OK;
+  }
   return CheckForRecursiveLoad(aURI);
 }
 
 NS_IMETHODIMP
 nsFrameLoader::GetDocShell(nsIDocShell **aDocShell)
 {
   *aDocShell = nsnull;
 
   // If we have an owner, make sure we have a docshell and return
   // that. If not, we're most likely in the middle of being torn down,
   // then we just return null.
   if (mOwnerContent) {
-    nsresult rv = EnsureDocShell();
-    NS_ENSURE_SUCCESS(rv, rv);
+    nsresult rv = MaybeCreateDocShell();
+    if (NS_FAILED(rv))
+      return rv;
+    if (mRemoteFrame) {
+      NS_WARNING("No docshells for remote frames!");
+      return NS_ERROR_NOT_AVAILABLE;
+    }
+    NS_ASSERTION(mDocShell,
+                 "MaybeCreateDocShell succeeded, but null mDocShell");
   }
 
   *aDocShell = mDocShell;
   NS_IF_ADDREF(*aDocShell);
 
   return NS_OK;
 }
 
@@ -822,24 +845,69 @@ nsFrameLoader::Destroy()
 
 NS_IMETHODIMP
 nsFrameLoader::GetDepthTooGreat(PRBool* aDepthTooGreat)
 {
   *aDepthTooGreat = mDepthTooGreat;
   return NS_OK;
 }
 
+#ifdef MOZ_IPC
+bool
+nsFrameLoader::ShouldUseRemoteProcess()
+{
+  // Check for *disabled* multi-process first: environment, prefs, attribute
+  // Then check for *enabled* multi-process pref: attribute, prefs
+  // Default is not-remote.
+
+  if (PR_GetEnv("MOZ_DISABLE_OOP_TABS")) {
+    return false;
+  }
+
+  PRBool remoteDisabled = nsContentUtils::GetBoolPref("dom.ipc.tabs.disabled",
+                                                      PR_FALSE);
+  if (remoteDisabled) {
+    return false;
+  }
+
+  static nsIAtom* const *const remoteValues[] = {
+    &nsGkAtoms::_false,
+    &nsGkAtoms::_true,
+    nsnull
+  };
+
+  switch (mOwnerContent->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::Remote,
+                                         remoteValues, eCaseMatters)) {
+  case 0:
+    return false;
+  case 1:
+    return true;
+  }
+
+  PRBool remoteEnabled = nsContentUtils::GetBoolPref("dom.ipc.tabs.enabled",
+                                                     PR_FALSE);
+  return (bool) remoteEnabled;
+}
+#endif
+
 nsresult
-nsFrameLoader::EnsureDocShell()
+nsFrameLoader::MaybeCreateDocShell()
 {
-  if (mDocShell) {
+  if (mDocShell || mRemoteFrame) {
     return NS_OK;
   }
   NS_ENSURE_STATE(!mDestroyCalled);
 
+#ifdef MOZ_IPC
+  if (ShouldUseRemoteProcess()) {
+    mRemoteFrame = true;
+    return NS_OK;
+  }
+#endif
+
   // Get our parent docshell off the document of mOwnerContent
   // XXXbz this is such a total hack.... We really need to have a
   // better setup for doing this.
   nsIDocument* doc = mOwnerContent->GetDocument();
   if (!doc) {
     return NS_ERROR_UNEXPECTED;
   }
 
@@ -853,16 +921,17 @@ nsFrameLoader::EnsureDocShell()
 
   // Create the docshell...
   mDocShell = do_CreateInstance("@mozilla.org/docshell;1");
   NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE);
 
   // Get the frame name and tell the docshell about it.
   nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mDocShell));
   NS_ENSURE_TRUE(docShellAsItem, NS_ERROR_FAILURE);
+
   nsAutoString frameName;
 
   PRInt32 namespaceID = mOwnerContent->GetNameSpaceID();
   if (namespaceID == kNameSpaceID_XHTML && !mOwnerContent->IsInHTMLDocument()) {
     mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::id, frameName);
   } else {
     mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::name, frameName);
     // XXX if no NAME then use ID, after a transition period this will be
@@ -959,19 +1028,28 @@ nsFrameLoader::GetURL(nsString& aURI)
   } else {
     mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::src, aURI);
   }
 }
 
 nsresult
 nsFrameLoader::CheckForRecursiveLoad(nsIURI* aURI)
 {
+  nsresult rv;
+
   mDepthTooGreat = PR_FALSE;
-  nsresult rv = EnsureDocShell();
-  NS_ENSURE_SUCCESS(rv, rv);
+  rv = MaybeCreateDocShell();
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  NS_ASSERTION(!mRemoteFrame,
+               "Shouldn't call CheckForRecursiveLoad on remote frames.");
+  if (!mDocShell) {
+    return NS_ERROR_FAILURE;
+  }
 
   nsCOMPtr<nsIDocShellTreeItem> treeItem = do_QueryInterface(mDocShell);
   NS_ASSERTION(treeItem, "docshell must be a treeitem!");
   
   PRInt32 ourType;
   rv = treeItem->GetItemType(&ourType);
   if (NS_SUCCEEDED(rv) && ourType != nsIDocShellTreeItem::typeContent) {
     // No need to do recursion-protection here XXXbz why not??  Do we really
@@ -1085,16 +1163,18 @@ nsFrameLoader::UpdateBaseWindowPositionA
       // GetPositionAndSize() killed us
       return NS_OK;
     }
 
     nsIntSize size = GetSubDocumentSize(aIFrame);
 
     baseWindow->SetPositionAndSize(x, y, size.width, size.height, PR_FALSE);
   }
+
+  return NS_OK;
 }
 
 nsIntSize
 nsFrameLoader::GetSubDocumentSize(const nsIFrame *aIFrame)
 {
   nsSize docSizeAppUnits;
   nsPresContext* presContext = aIFrame->PresContext();
   nsCOMPtr<nsIDOMHTMLFrameElement> frameElem = 
@@ -1107,31 +1187,17 @@ nsFrameLoader::GetSubDocumentSize(const 
   return nsIntSize(presContext->AppUnitsToDevPixels(docSizeAppUnits.width),
                    presContext->AppUnitsToDevPixels(docSizeAppUnits.height));
 }
 
 #ifdef MOZ_IPC
 PRBool
 nsFrameLoader::TryNewProcess()
 {
-  if (PR_GetEnv("MOZ_DISABLE_OOP_TABS")) {
-      return PR_FALSE;
-  }
-
-  nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
-  if (!prefs) {
-      return PR_FALSE;
-  }
-
-  PRBool oopTabsEnabled = PR_FALSE;
-  prefs->GetBoolPref("dom.ipc.tabs.enabled", &oopTabsEnabled);
-
-  if (!oopTabsEnabled) {
-      return PR_FALSE;
-  }
+  NS_ASSERTION(!mChildProcess, "TryNewProcess called with a process already?");
 
   nsIDocument* doc = mOwnerContent->GetDocument();
   if (!doc) {
     return PR_FALSE;
   }
 
   if (doc->GetDisplayDocument()) {
     // Don't allow subframe loads in external reference documents
--- a/content/base/src/nsFrameLoader.h
+++ b/content/base/src/nsFrameLoader.h
@@ -68,18 +68,18 @@ protected:
   nsFrameLoader(nsIContent *aOwner) :
     mOwnerContent(aOwner),
     mDepthTooGreat(PR_FALSE),
     mIsTopLevelContent(PR_FALSE),
     mDestroyCalled(PR_FALSE),
     mNeedsAsyncDestroy(PR_FALSE),
     mInSwap(PR_FALSE)
 #ifdef MOZ_IPC
+    , mRemoteFrame(false)
     , mChildProcess(nsnull)
-    , mTriedNewProcess(PR_FALSE)
 #endif
   {}
 
 public:
   ~nsFrameLoader() {
     mNeedsAsyncDestroy = PR_TRUE;
     nsFrameLoader::Destroy();
   }
@@ -97,18 +97,26 @@ public:
   // The guts of an nsIFrameLoaderOwner::SwapFrameLoader implementation.  A
   // frame loader owner needs to call this, and pass in the two references to
   // nsRefPtrs for frame loaders that need to be swapped.
   nsresult SwapWithOtherLoader(nsFrameLoader* aOther,
                                nsRefPtr<nsFrameLoader>& aFirstToSwap,
                                nsRefPtr<nsFrameLoader>& aSecondToSwap);
 private:
 
-  NS_HIDDEN_(nsresult) EnsureDocShell();
-  NS_HIDDEN_(void) GetURL(nsString& aURL);
+#ifdef MOZ_IPC
+  bool ShouldUseRemoteProcess();
+#endif
+
+  /**
+   * If we are an IPC frame, set mRemoteFrame. Otherwise, create and
+   * initialize mDocShell.
+   */
+  nsresult MaybeCreateDocShell();
+  void GetURL(nsString& aURL);
 
   // Properly retrieves documentSize of any subdocument type.
   NS_HIDDEN_(nsIntSize) GetSubDocumentSize(const nsIFrame *aIFrame);
 
   // Updates the subdocument position and size. This gets called only
   // when we have our own in-process DocShell.
   NS_HIDDEN_(nsresult) UpdateBaseWindowPositionAndSize(nsIFrame *aIFrame);
   nsresult CheckURILoad(nsIURI* aURI);
@@ -123,15 +131,15 @@ private:
   nsIContent *mOwnerContent; // WEAK
   PRPackedBool mDepthTooGreat : 1;
   PRPackedBool mIsTopLevelContent : 1;
   PRPackedBool mDestroyCalled : 1;
   PRPackedBool mNeedsAsyncDestroy : 1;
   PRPackedBool mInSwap : 1;
 
 #ifdef MOZ_IPC
+  bool mRemoteFrame;
   // XXX leaking
   mozilla::dom::TabParent* mChildProcess;
-  PRBool mTriedNewProcess;
 #endif
 };
 
 #endif
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -1693,16 +1693,19 @@ GK_ATOM(Taiwanese, "zh-TW")
 GK_ATOM(HongKongChinese, "zh-HK")
 GK_ATOM(Unicode, "x-unicode")
 
 // Names for editor transactions
 GK_ATOM(TypingTxnName, "Typing")
 GK_ATOM(IMETxnName, "IME")
 GK_ATOM(DeleteTxnName, "Deleting")
 
+// IPC stuff
+GK_ATOM(Remote, "remote")
+
 // Names for system metrics
 GK_ATOM(scrollbar_start_backward, "scrollbar-start-backward")
 GK_ATOM(scrollbar_start_forward, "scrollbar-start-forward")
 GK_ATOM(scrollbar_end_backward, "scrollbar-end-backward")
 GK_ATOM(scrollbar_end_forward, "scrollbar-end-forward")
 GK_ATOM(scrollbar_thumb_proportional, "scrollbar-thumb-proportional")
 GK_ATOM(images_in_menus, "images-in-menus")
 GK_ATOM(images_in_buttons, "images-in-buttons")
--- a/dom/ipc/test.xul
+++ b/dom/ipc/test.xul
@@ -17,10 +17,10 @@
 
   <toolbar id="controls">
     <toolbarbutton label="Back"/>
     <toolbarbutton label="Forward"/>
     <textbox onchange="loadURL(this.value)" flex="1" id="URL"/>
     <toolbarbutton onclick="restart()" label="Recover"/>
   </toolbar>
 
-  <iframe type="content" src="http://www.google.com/" flex="1" id="page"/>
+  <iframe type="content" src="http://www.google.com/" flex="1" id="page" remote="true"/>
 </window>