diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index daab9d10ec81..e5941c425d5b 100644 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -4132,7 +4132,7 @@ function nsBrowserAccess() { } nsBrowserAccess.prototype = { QueryInterface: XPCOMUtils.generateQI([Ci.nsIBrowserDOMWindow, Ci.nsISupports]), - _openURIInNewTab: function(aURI, aOpener, aIsExternal) { + _openURIInNewTab: function(aURI, aOpener, aIsExternal, aEnsureNonRemote=false) { let win, needToFocusWin; // try the current window. if we're in a popup, fall back on the most recent browser window @@ -4164,6 +4164,15 @@ nsBrowserAccess.prototype = { inBackground: loadInBackground}); let browser = win.gBrowser.getBrowserForTab(tab); + // It's possible that we've been asked to open a new non-remote + // browser in a window that defaults to having remote browsers - + // this can happen if we're opening the new tab due to a window.open + // or _blank anchor in a non-remote browser. If so, we have to force + // the newly opened browser to also not be remote. + if (win.gMultiProcessBrowser && aEnsureNonRemote) { + win.gBrowser.updateBrowserRemoteness(browser, false); + } + if (needToFocusWin || (!loadInBackground && aIsExternal)) win.focus(); @@ -4171,6 +4180,14 @@ nsBrowserAccess.prototype = { }, openURI: function (aURI, aOpener, aWhere, aContext) { + // This function should only ever be called if we're opening a URI + // from a non-remote browser window (via nsContentTreeOwner). + if (aOpener && Cu.isCrossProcessWrapper(aOpener)) { + Cu.reportError("nsBrowserAccess.openURI was passed a CPOW for aOpener. " + + "openURI should only ever be called from non-remote browsers."); + throw Cr.NS_ERROR_FAILURE; + } + var newWindow = null; var isExternal = (aContext == Ci.nsIBrowserDOMWindow.OPEN_EXTERNAL); @@ -4196,7 +4213,7 @@ nsBrowserAccess.prototype = { newWindow = openDialog(getBrowserURL(), "_blank", "all,dialog=no", url, null, null, null); break; case Ci.nsIBrowserDOMWindow.OPEN_NEWTAB : - let browser = this._openURIInNewTab(aURI, aOpener, isExternal); + let browser = this._openURIInNewTab(aURI, aOpener, isExternal, true); if (browser) newWindow = browser.contentWindow; break; diff --git a/browser/base/content/test/general/browser.ini b/browser/base/content/test/general/browser.ini index b0261c5b8fb0..5c99c1423a9d 100644 --- a/browser/base/content/test/general/browser.ini +++ b/browser/base/content/test/general/browser.ini @@ -483,3 +483,4 @@ skip-if = e10s skip-if = e10s # Bug ?????? - test directly manipulates content (content.document.getElementById) [browser_bug1045809.js] skip-if = e10s +[browser_bug1047603.js] diff --git a/browser/base/content/test/general/browser_bug1047603.js b/browser/base/content/test/general/browser_bug1047603.js new file mode 100644 index 000000000000..8dce62150307 --- /dev/null +++ b/browser/base/content/test/general/browser_bug1047603.js @@ -0,0 +1,139 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +const OPEN_LOCATION_PREF = "browser.link.open_newwindow"; +const NON_REMOTE_PAGE = "about:crashes"; + +const SIMPLE_PAGE_HTML = ` +Open a window +`; + +function frame_script() { + addMessageListener("test:click", (message) => { + let element = content.document.getElementById("testAnchor"); + element.click(); + }); + sendAsyncMessage("test:ready"); +} + +/** + * Returns a Promise that resolves once the frame_script is loaded + * in the browser, and has seen the DOMContentLoaded event. + */ +function waitForFrameScriptReady(mm) { + return new Promise((resolve, reject) => { + mm.addMessageListener("test:ready", function onTestReady() { + mm.removeMessageListener("test:ready", onTestReady); + resolve(); + }); + }); +} + +/** + * Takes some browser in some window, and forces that browser + * to become non-remote, and then navigates it to a page that + * we're not supposed to be displaying remotely. Returns a + * Promise that resolves when the browser is no longer remote. + */ +function prepareNonRemoteBrowser(aWindow, browser) { + aWindow.gBrowser.updateBrowserRemoteness(browser, false); + browser.loadURI(NON_REMOTE_PAGE); + return new Promise((resolve, reject) => { + waitForCondition(() => !browser.isRemoteBrowser, () => { + resolve(); + }, "Waiting for browser to become non-remote"); + }) +} + +registerCleanupFunction(() => { + Services.prefs.clearUserPref(OPEN_LOCATION_PREF); +}); + +/** + * Test that if we open a new tab from a link in a non-remote + * browser in an e10s window, that the new tab's browser is also + * not remote. Also tests with a private browsing window. + */ +add_task(function* test_new_tab() { + let normalWindow = yield promiseOpenAndLoadWindow({ + remote: true + }, true); + let privateWindow = yield promiseOpenAndLoadWindow({ + remote: true, + private: true, + }, true); + + for (let testWindow of [normalWindow, privateWindow]) { + let testBrowser = testWindow.gBrowser.selectedBrowser; + yield prepareNonRemoteBrowser(testWindow, testBrowser); + + // Get our framescript ready + let mm = testBrowser.messageManager; + mm.loadFrameScript("data:,(" + frame_script.toString() + ")();", true); + let readyPromise = waitForFrameScriptReady(mm); + yield readyPromise; + + // Inject our test HTML into our non-remote tab. + testBrowser.contentDocument.body.innerHTML = SIMPLE_PAGE_HTML; + + // Click on the link in the browser, and wait for the new tab. + mm.sendAsyncMessage("test:click"); + let tabOpenEvent = yield waitForNewTab(testWindow.gBrowser); + let newTab = tabOpenEvent.target; + ok(!newTab.linkedBrowser.isRemoteBrowser, + "The opened browser should not be remote."); + + testWindow.gBrowser.removeTab(newTab); + } + + normalWindow.close(); + privateWindow.close(); +}); + +/** + * Test that if we open a new window from a link in a non-remote + * browser in an e10s window, that the new window is not an e10s + * window. Also tests with a private browsing window. + */ +add_task(function* test_new_window() { + let normalWindow = yield promiseOpenAndLoadWindow({ + remote: true + }, true); + let privateWindow = yield promiseOpenAndLoadWindow({ + remote: true, + private: true, + }, true); + + // Fiddle with the prefs so that we open target="_blank" links + // in new windows instead of new tabs. + Services.prefs.setIntPref(OPEN_LOCATION_PREF, + Ci.nsIBrowserDOMWindow.OPEN_NEWWINDOW); + + for (let testWindow of [normalWindow, privateWindow]) { + let testBrowser = testWindow.gBrowser.selectedBrowser; + yield prepareNonRemoteBrowser(testWindow, testBrowser); + + // Get our framescript ready + let mm = testBrowser.messageManager; + mm.loadFrameScript("data:,(" + frame_script.toString() + ")();", true); + let readyPromise = waitForFrameScriptReady(mm); + yield readyPromise; + + // Inject our test HTML into our non-remote window. + testBrowser.contentDocument.body.innerHTML = SIMPLE_PAGE_HTML; + + // Click on the link in the browser, and wait for the new window. + let windowOpenPromise = promiseTopicObserved("browser-delayed-startup-finished"); + mm.sendAsyncMessage("test:click"); + let [newWindow] = yield windowOpenPromise; + ok(!newWindow.gMultiProcessBrowser, + "The opened window should not be an e10s window."); + newWindow.close(); + } + + normalWindow.close(); + privateWindow.close(); + + Services.prefs.clearUserPref(OPEN_LOCATION_PREF); +}); diff --git a/browser/base/content/test/general/head.js b/browser/base/content/test/general/head.js index 3e45642f45f8..5f15a517d286 100644 --- a/browser/base/content/test/general/head.js +++ b/browser/base/content/test/general/head.js @@ -665,3 +665,7 @@ function assertWebRTCIndicatorStatus(expected) { } } } + +function waitForNewTab(aTabBrowser) { + return promiseWaitForEvent(aTabBrowser.tabContainer, "TabOpen"); +} diff --git a/xpfe/appshell/nsAppShellService.cpp b/xpfe/appshell/nsAppShellService.cpp index 5da29064e39c..a39fb40d8c8d 100644 --- a/xpfe/appshell/nsAppShellService.cpp +++ b/xpfe/appshell/nsAppShellService.cpp @@ -630,7 +630,7 @@ nsAppShellService::JustCreateTopWindow(nsIXULWindow *aParent, } if (parentContext) { - isUsingRemoteTabs = parentContext->UseRemoteTabs(); + isUsingRemoteTabs = parentContext->UseRemoteTabs() && aOpeningTab; } nsCOMPtr newDomWin =