From 1590ebd9cf5b308b60f849b9aee92a8968cbe621 Mon Sep 17 00:00:00 2001 From: Dave Townsend Date: Thu, 5 Feb 2015 08:09:15 -0800 Subject: [PATCH] Bug 1083281: Use flags to determine which chrome and about URIs are loaded in the content process. r=mconley, r=bsmedberg, r=jduell, r=mratcliffe --HG-- extra : rebase_source : beda0088e7715eeb41525b0123f308068745bd80 --- browser/base/content/browser.js | 10 +- browser/base/content/tabbrowser.xml | 20 ++- browser/base/content/test/general/browser.ini | 3 + .../test/general/browser_aboutAccounts.js | 10 +- ...025195_switchToTabHavingURI_aOpenParams.js | 5 + .../general/browser_e10s_about_process.js | 114 +++++++++++++ .../general/browser_e10s_chrome_process.js | 150 ++++++++++++++++++ .../general/test_process_flags_chrome.html | 10 ++ browser/components/about/AboutRedirector.cpp | 2 + .../sessionstore/test/browser_frametree.js | 4 +- browser/components/sessionstore/test/head.js | 1 + .../test/browser_styleeditor_loading.js | 2 +- browser/modules/E10SUtils.jsm | 61 +++++-- chrome/nsChromeRegistry.cpp | 64 ++++++++ chrome/nsChromeRegistry.h | 33 ++-- chrome/nsChromeRegistryChrome.cpp | 27 +--- chrome/nsChromeRegistryChrome.h | 21 +-- chrome/nsChromeRegistryContent.cpp | 20 +-- chrome/nsChromeRegistryContent.h | 21 +-- chrome/nsIChromeRegistry.idl | 16 +- docshell/base/nsAboutRedirector.cpp | 1 + netwerk/protocol/about/nsAboutBlank.cpp | 1 + netwerk/protocol/about/nsIAboutModule.idl | 10 ++ testing/mochitest/runtests.py | 2 + xpcom/components/ManifestParser.cpp | 36 +++-- 25 files changed, 527 insertions(+), 117 deletions(-) create mode 100644 browser/base/content/test/general/browser_e10s_about_process.js create mode 100644 browser/base/content/test/general/browser_e10s_chrome_process.js create mode 100644 browser/base/content/test/general/test_process_flags_chrome.html diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index a5d21f6ab70..f18d2e5555e 100644 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -823,10 +823,12 @@ function _loadURIWithFlags(browser, uri, flags, referrer, charset, postdata) { browser.userTypedClear++; } - let shouldBeRemote = gMultiProcessBrowser && - E10SUtils.shouldBrowserBeRemote(uri); + let process = browser.isRemoteBrowser ? Ci.nsIXULRuntime.PROCESS_TYPE_CONTENT + : Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT; + let mustChangeProcess = gMultiProcessBrowser && + !E10SUtils.canLoadURIInProcess(uri, process); try { - if (browser.isRemoteBrowser == shouldBeRemote) { + if (!mustChangeProcess) { browser.webNavigation.loadURI(uri, flags, referrer, postdata, null); } else { LoadInOtherProcess(browser, { @@ -840,7 +842,7 @@ function _loadURIWithFlags(browser, uri, flags, referrer, charset, postdata) { // We might lose history that way but at least the browser loaded a page. // This might be necessary if SessionStore wasn't initialized yet i.e. // when the homepage is a non-remote page. - gBrowser.updateBrowserRemoteness(browser, shouldBeRemote); + gBrowser.updateBrowserRemotenessByURL(browser, uri); browser.webNavigation.loadURI(uri, flags, referrer, postdata, null); } finally { if (browser.userTypedClear) { diff --git a/browser/base/content/tabbrowser.xml b/browser/base/content/tabbrowser.xml index 963467ee37c..ab71616211f 100644 --- a/browser/base/content/tabbrowser.xml +++ b/browser/base/content/tabbrowser.xml @@ -1514,9 +1514,18 @@ @@ -1690,7 +1699,10 @@ t.setAttribute("onerror", "this.removeAttribute('image');"); t.className = "tabbrowser-tab"; - let remote = gMultiProcessBrowser && E10SUtils.shouldBrowserBeRemote(aURI); + // The new browser should be remote if this is an e10s window and + // the uri to load can be loaded remotely. + let remote = gMultiProcessBrowser && + E10SUtils.canLoadURIInProcess(aURI, Ci.nsIXULRuntime.PROCESS_TYPE_CONTENT); if (remote) t.setAttribute("remote", "true"); diff --git a/browser/base/content/test/general/browser.ini b/browser/base/content/test/general/browser.ini index f8bf8866f2a..d0c59cd0a73 100644 --- a/browser/base/content/test/general/browser.ini +++ b/browser/base/content/test/general/browser.ini @@ -79,6 +79,7 @@ support-files = test_bug628179.html test_bug839103.html test_bug959531.html + test_process_flags_chrome.html test_wyciwyg_copying.html title_test.svg video.ogg @@ -480,6 +481,8 @@ skip-if = e10s skip-if = e10s # Bug 1100687 - test directly manipulates content (content.document.getElementById) [browser_bug1045809.js] [browser_e10s_switchbrowser.js] +[browser_e10s_about_process.js] +[browser_e10s_chrome_process.js] [browser_blockHPKP.js] skip-if = e10s # bug 1100687 - test directly manipulates content (content.document.getElementById) [browser_mcb_redirect.js] diff --git a/browser/base/content/test/general/browser_aboutAccounts.js b/browser/base/content/test/general/browser_aboutAccounts.js index c89399215bd..ec15928ed56 100644 --- a/browser/base/content/test/general/browser_aboutAccounts.js +++ b/browser/base/content/test/general/browser_aboutAccounts.js @@ -217,10 +217,10 @@ let gTests = [ yield OS.File.writeAtomic(fxAccountsStorage, JSON.stringify(signedInUser)); info("Wrote file " + fxAccountsStorage); - // this is a little subtle - we load about:blank so we get a tab, then - // we send a message which does both (a) load the URL we want and (b) mocks - // the default profile path used by about:accounts. - let tab = yield promiseNewTabLoadEvent("about:blank?"); + // this is a little subtle - we load about:robots so we get a non-remote + // tab, then we send a message which does both (a) load the URL we want and + // (b) mocks the default profile path used by about:accounts. + let tab = yield promiseNewTabLoadEvent("about:robots"); let readyPromise = promiseOneMessage(tab, "test:load-with-mocked-profile-path-response"); let mm = tab.linkedBrowser.messageManager; @@ -261,7 +261,7 @@ let gTests = [ mockDir.createUnique(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY); // but leave it empty, so we don't think a user is logged in. - let tab = yield promiseNewTabLoadEvent("about:blank?"); + let tab = yield promiseNewTabLoadEvent("about:robots"); let readyPromise = promiseOneMessage(tab, "test:load-with-mocked-profile-path-response"); let mm = tab.linkedBrowser.messageManager; diff --git a/browser/base/content/test/general/browser_bug1025195_switchToTabHavingURI_aOpenParams.js b/browser/base/content/test/general/browser_bug1025195_switchToTabHavingURI_aOpenParams.js index 0ff2e8dc26d..fff36eeeea8 100644 --- a/browser/base/content/test/general/browser_bug1025195_switchToTabHavingURI_aOpenParams.js +++ b/browser/base/content/test/general/browser_bug1025195_switchToTabHavingURI_aOpenParams.js @@ -13,8 +13,13 @@ add_task(function test_ignoreFragment() { switchTab("about:home#1", true); switchTab("about:mozilla", true); + + let hashChangePromise = new Promise(resolve => { + tabRefAboutHome.linkedBrowser.contentWindow.addEventListener("hashchange", resolve, false); + }); switchTab("about:home#2", true, { ignoreFragment: true }); is(tabRefAboutHome, gBrowser.selectedTab, "The same about:home tab should be switched to"); + yield hashChangePromise; is(gBrowser.currentURI.ref, "2", "The ref should be updated to the new ref"); switchTab("about:mozilla", true); switchTab("about:home#1", false); diff --git a/browser/base/content/test/general/browser_e10s_about_process.js b/browser/base/content/test/general/browser_e10s_about_process.js new file mode 100644 index 00000000000..76483ac6dea --- /dev/null +++ b/browser/base/content/test/general/browser_e10s_about_process.js @@ -0,0 +1,114 @@ +const CHROME_PROCESS = Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT; +const CONTENT_PROCESS = Ci.nsIXULRuntime.PROCESS_TYPE_CONTENT; + +const CHROME = { + id: "cb34538a-d9da-40f3-b61a-069f0b2cb9fb", + path: "test-chrome", + flags: 0, +} +const CANREMOTE = { + id: "2480d3e1-9ce4-4b84-8ae3-910b9a95cbb3", + path: "test-allowremote", + flags: Ci.nsIAboutModule.URI_CAN_LOAD_IN_CHILD, +} +const MUSTREMOTE = { + id: "f849cee5-e13e-44d2-981d-0fb3884aaead", + path: "test-mustremote", + flags: Ci.nsIAboutModule.URI_MUST_LOAD_IN_CHILD, +} + +const TEST_MODULES = [ + CHROME, + CANREMOTE, + MUSTREMOTE +] + +function AboutModule() { +} + +AboutModule.prototype = { + newChannel: function(aURI, aLoadInfo) { + throw Components.results.NS_ERROR_NOT_IMPLEMENTED; + }, + + getURIFlags: function(aURI) { + for (let module of TEST_MODULES) { + if (aURI.path.startsWith(module.path)) { + return module.flags; + } + } + + ok(false, "Called getURIFlags for an unknown page " + aURI.spec); + return 0; + }, + + getIndexedDBOriginPostfix: function(aURI) { + return null; + }, + + QueryInterface: XPCOMUtils.generateQI([Ci.nsIAboutModule]) +}; + +let AboutModuleFactory = { + createInstance: function(aOuter, aIID) { + if (aOuter) + throw Components.results.NS_ERROR_NO_AGGREGATION; + return new AboutModule().QueryInterface(aIID); + }, + + lockFactory: function(aLock) { + throw Components.results.NS_ERROR_NOT_IMPLEMENTED; + }, + + QueryInterface: XPCOMUtils.generateQI([Ci.nsIFactory]) +}; + +add_task(function* init() { + let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar); + for (let module of TEST_MODULES) { + registrar.registerFactory(Components.ID(module.id), "", + "@mozilla.org/network/protocol/about;1?what=" + module.path, + AboutModuleFactory); + } +}); + +registerCleanupFunction(() => { + let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar); + for (let module of TEST_MODULES) { + registrar.unregisterFactory(Components.ID(module.id), AboutModuleFactory); + } +}); + +function test_url(url, chromeResult, contentResult) { + is(E10SUtils.canLoadURIInProcess(url, CHROME_PROCESS), + chromeResult, "Check URL in chrome process."); + is(E10SUtils.canLoadURIInProcess(url, CONTENT_PROCESS), + contentResult, "Check URL in content process."); + + is(E10SUtils.canLoadURIInProcess(url + "#foo", CHROME_PROCESS), + chromeResult, "Check URL with ref in chrome process."); + is(E10SUtils.canLoadURIInProcess(url + "#foo", CONTENT_PROCESS), + contentResult, "Check URL with ref in content process."); + + is(E10SUtils.canLoadURIInProcess(url + "?foo", CHROME_PROCESS), + chromeResult, "Check URL with query in chrome process."); + is(E10SUtils.canLoadURIInProcess(url + "?foo", CONTENT_PROCESS), + contentResult, "Check URL with query in content process."); + + is(E10SUtils.canLoadURIInProcess(url + "?foo#bar", CHROME_PROCESS), + chromeResult, "Check URL with query and ref in chrome process."); + is(E10SUtils.canLoadURIInProcess(url + "?foo#bar", CONTENT_PROCESS), + contentResult, "Check URL with query and ref in content process."); +} + +add_task(function* test_chrome() { + test_url("about:" + CHROME.path, true, false); +}); + +add_task(function* test_any() { + test_url("about:" + CANREMOTE.path, true, true); +}); + +add_task(function* test_remote() { + test_url("about:" + MUSTREMOTE.path, false, true); +}); diff --git a/browser/base/content/test/general/browser_e10s_chrome_process.js b/browser/base/content/test/general/browser_e10s_chrome_process.js new file mode 100644 index 00000000000..64187d3b291 --- /dev/null +++ b/browser/base/content/test/general/browser_e10s_chrome_process.js @@ -0,0 +1,150 @@ +// Returns a function suitable for add_task which loads startURL, runs +// transitionTask and waits for endURL to load, checking that the URLs were +// loaded in the correct process. +function makeTest(name, startURL, startProcessIsRemote, endURL, endProcessIsRemote, transitionTask) { + return function*() { + info("Running test " + name + ", " + transitionTask.name); + let browser = gBrowser.selectedBrowser; + + // In non-e10s nothing should be remote + if (!gMultiProcessBrowser) { + startProcessIsRemote = false; + endProcessIsRemote = false; + } + + // Load the initial URL and make sure we are in the right initial process + info("Loading initial URL"); + browser.loadURI(startURL); + yield waitForDocLoadComplete(); + + is(browser.currentURI.spec, startURL, "Shouldn't have been redirected"); + is(browser.isRemoteBrowser, startProcessIsRemote, "Should be displayed in the right process"); + + let docLoadedPromise = waitForDocLoadComplete(); + let asyncTask = Task.async(transitionTask); + let expectSyncChange = yield asyncTask(browser, endURL); + if (expectSyncChange) { + is(browser.isRemoteBrowser, endProcessIsRemote, "Should have switched to the right process synchronously"); + } + yield docLoadedPromise; + + is(browser.currentURI.spec, endURL, "Should have made it to the final URL"); + is(browser.isRemoteBrowser, endProcessIsRemote, "Should be displayed in the right process"); + } +} + +const CHROME_PROCESS = Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT; +const CONTENT_PROCESS = Ci.nsIXULRuntime.PROCESS_TYPE_CONTENT; +const PATH = (getRootDirectory(gTestPath) + "test_process_flags_chrome.html").replace("chrome://mochitests", ""); + +const CHROME = "chrome://mochitests" + PATH; +const CANREMOTE = "chrome://mochitests-any" + PATH; +const MUSTREMOTE = "chrome://mochitests-content" + PATH; + +add_task(function* init() { + gBrowser.selectedTab = gBrowser.addTab("about:blank"); +}); + +registerCleanupFunction(() => { + gBrowser.removeCurrentTab(); +}); + +function test_url(url, chromeResult, contentResult) { + is(E10SUtils.canLoadURIInProcess(url, CHROME_PROCESS), + chromeResult, "Check URL in chrome process."); + is(E10SUtils.canLoadURIInProcess(url, CONTENT_PROCESS), + contentResult, "Check URL in content process."); + + is(E10SUtils.canLoadURIInProcess(url + "#foo", CHROME_PROCESS), + chromeResult, "Check URL with ref in chrome process."); + is(E10SUtils.canLoadURIInProcess(url + "#foo", CONTENT_PROCESS), + contentResult, "Check URL with ref in content process."); + + is(E10SUtils.canLoadURIInProcess(url + "?foo", CHROME_PROCESS), + chromeResult, "Check URL with query in chrome process."); + is(E10SUtils.canLoadURIInProcess(url + "?foo", CONTENT_PROCESS), + contentResult, "Check URL with query in content process."); + + is(E10SUtils.canLoadURIInProcess(url + "?foo#bar", CHROME_PROCESS), + chromeResult, "Check URL with query and ref in chrome process."); + is(E10SUtils.canLoadURIInProcess(url + "?foo#bar", CONTENT_PROCESS), + contentResult, "Check URL with query and ref in content process."); +} + +add_task(function* test_chrome() { + test_url(CHROME, true, false); +}); + +add_task(function* test_any() { + test_url(CANREMOTE, true, true); +}); + +add_task(function* test_remote() { + test_url(MUSTREMOTE, false, true); +}); + +// The set of page transitions +let TESTS = [ + [ + "chrome -> chrome", + CHROME, false, + CHROME, false, + ], + [ + "chrome -> canremote", + CHROME, false, + CANREMOTE, false, + ], + [ + "chrome -> mustremote", + CHROME, false, + MUSTREMOTE, true, + ], + [ + "remote -> chrome", + MUSTREMOTE, true, + CHROME, false, + ], + [ + "remote -> canremote", + MUSTREMOTE, true, + CANREMOTE, true, + ], + [ + "remote -> mustremote", + MUSTREMOTE, true, + MUSTREMOTE, true, + ], +]; + +// The different ways to transition from one page to another +let TRANSITIONS = [ +// Loads the new page by calling browser.loadURI directly +function* loadURI(browser, uri) { + info("Calling browser.loadURI"); + browser.loadURI(uri); + return true; +}, + +// Loads the new page by finding a link with the right href in the document and +// clicking it +function* clickLink(browser, uri) { + info("Clicking link"); + + function frame_script(uri) { + let link = content.document.querySelector("a[href='" + uri + "']"); + link.click(); + } + + browser.messageManager.loadFrameScript("data:,(" + frame_script.toString() + ")(" + JSON.stringify(uri) + ");", false); + + return false; +}, +]; + +// Creates a set of test tasks, one for each combination of TESTS and TRANSITIONS. +for (let test of TESTS) { + for (let transition of TRANSITIONS) { + add_task(makeTest(...test, transition)); + } +} diff --git a/browser/base/content/test/general/test_process_flags_chrome.html b/browser/base/content/test/general/test_process_flags_chrome.html new file mode 100644 index 00000000000..adcbf03403f --- /dev/null +++ b/browser/base/content/test/general/test_process_flags_chrome.html @@ -0,0 +1,10 @@ + + + + +

chrome: test page

+

chrome

+

canremote

+

mustremote

+ + diff --git a/browser/components/about/AboutRedirector.cpp b/browser/components/about/AboutRedirector.cpp index 04065cc4fc6..0e0cedcde45 100644 --- a/browser/components/about/AboutRedirector.cpp +++ b/browser/components/about/AboutRedirector.cpp @@ -42,6 +42,7 @@ static RedirEntry kRedirMap[] = { #endif { "certerror", "chrome://browser/content/certerror/aboutCertError.xhtml", nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT | + nsIAboutModule::URI_CAN_LOAD_IN_CHILD | nsIAboutModule::ALLOW_SCRIPT | nsIAboutModule::HIDE_FROM_ABOUTABOUT }, { "socialerror", "chrome://browser/content/aboutSocialError.xhtml", @@ -83,6 +84,7 @@ static RedirEntry kRedirMap[] = { #endif { "home", "chrome://browser/content/abouthome/aboutHome.xhtml", nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT | + nsIAboutModule::URI_MUST_LOAD_IN_CHILD | nsIAboutModule::ALLOW_SCRIPT | nsIAboutModule::ENABLE_INDEXED_DB }, { "newtab", "chrome://browser/content/newtab/newTab.xul", diff --git a/browser/components/sessionstore/test/browser_frametree.js b/browser/components/sessionstore/test/browser_frametree.js index 2d4ae01512d..a342f8c66d5 100644 --- a/browser/components/sessionstore/test/browser_frametree.js +++ b/browser/components/sessionstore/test/browser_frametree.js @@ -3,8 +3,8 @@ "use strict"; -const URL = ROOT + "browser_frametree_sample.html"; -const URL_FRAMESET = ROOT + "browser_frametree_sample_frameset.html"; +const URL = HTTPROOT + "browser_frametree_sample.html"; +const URL_FRAMESET = HTTPROOT + "browser_frametree_sample_frameset.html"; /** * This ensures that loading a page normally, aborting a page load, reloading diff --git a/browser/components/sessionstore/test/head.js b/browser/components/sessionstore/test/head.js index bd5f27a63dd..60e10825b4f 100644 --- a/browser/components/sessionstore/test/head.js +++ b/browser/components/sessionstore/test/head.js @@ -6,6 +6,7 @@ const TAB_STATE_NEEDS_RESTORE = 1; const TAB_STATE_RESTORING = 2; const ROOT = getRootDirectory(gTestPath); +const HTTPROOT = ROOT.replace("chrome://mochitests/content/", "http://example.com/"); const FRAME_SCRIPTS = [ ROOT + "content.js", ROOT + "content-forms.js" diff --git a/browser/devtools/styleeditor/test/browser_styleeditor_loading.js b/browser/devtools/styleeditor/test/browser_styleeditor_loading.js index dec1f4b6c03..291381ee736 100644 --- a/browser/devtools/styleeditor/test/browser_styleeditor_loading.js +++ b/browser/devtools/styleeditor/test/browser_styleeditor_loading.js @@ -2,7 +2,7 @@ /* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ -const TESTCASE_URI = TEST_BASE + "longload.html"; +const TESTCASE_URI = TEST_BASE_HTTP + "longload.html"; function test() diff --git a/browser/modules/E10SUtils.jsm b/browser/modules/E10SUtils.jsm index 563c9331db6..abf0ddf1ada 100644 --- a/browser/modules/E10SUtils.jsm +++ b/browser/modules/E10SUtils.jsm @@ -10,38 +10,67 @@ const {interfaces: Ci, utils: Cu, classes: Cc} = Components; Cu.import("resource://gre/modules/Services.jsm"); +function getAboutModule(aURL) { + // Needs to match NS_GetAboutModuleName + let moduleName = aURL.path.replace(/[#?].*/, "").toLowerCase(); + let contract = "@mozilla.org/network/protocol/about;1?what=" + moduleName; + try { + return Cc[contract].getService(Ci.nsIAboutModule); + } + catch (e) { + // Either the about module isn't defined or it is broken. In either case + // ignore it. + return null; + } +} + this.E10SUtils = { - shouldBrowserBeRemote: function(aURL) { + canLoadURIInProcess: function(aURL, aProcess) { // loadURI in browser.xml treats null as about:blank if (!aURL) aURL = "about:blank"; - if (aURL.startsWith("about:") && - aURL.toLowerCase() != "about:home" && - aURL.toLowerCase() != "about:blank" && - !aURL.toLowerCase().startsWith("about:neterror") && - !aURL.toLowerCase().startsWith("about:certerror")) { - return false; + let processIsRemote = aProcess == Ci.nsIXULRuntime.PROCESS_TYPE_CONTENT; + + let canLoadRemote = true; + let mustLoadRemote = true; + + if (aURL.startsWith("about:")) { + let url = Services.io.newURI(aURL, null, null); + let module = getAboutModule(url); + // If the module doesn't exist then an error page will be loading, that + // should be ok to load in either process + if (module) { + let flags = module.getURIFlags(url); + canLoadRemote = !!(flags & Ci.nsIAboutModule.URI_CAN_LOAD_IN_CHILD); + mustLoadRemote = !!(flags & Ci.nsIAboutModule.URI_MUST_LOAD_IN_CHILD); + } } + if (aURL.startsWith("chrome:")) { + let url = Services.io.newURI(aURL, null, null); + let chromeReg = Cc["@mozilla.org/chrome/chrome-registry;1"]. + getService(Ci.nsIXULChromeRegistry); + canLoadRemote = chromeReg.canLoadURLRemotely(url); + mustLoadRemote = chromeReg.mustLoadURLRemotely(url); + } + + if (mustLoadRemote) + return processIsRemote; + + if (!canLoadRemote && processIsRemote) + return false; + return true; }, shouldLoadURI: function(aDocShell, aURI, aReferrer) { - // about:blank is the initial document and can load anywhere - if (aURI.spec == "about:blank") - return true; - // Inner frames should always load in the current process if (aDocShell.QueryInterface(Ci.nsIDocShellTreeItem).sameTypeParent) return true; // If the URI can be loaded in the current process then continue - let isRemote = Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT; - if (this.shouldBrowserBeRemote(aURI.spec) == isRemote) - return true; - - return false; + return this.canLoadURIInProcess(aURI.spec, Services.appinfo.processType); }, redirectLoad: function(aDocShell, aURI, aReferrer) { diff --git a/chrome/nsChromeRegistry.cpp b/chrome/nsChromeRegistry.cpp index fa96f22c4c1..dfdc4d1451f 100644 --- a/chrome/nsChromeRegistry.cpp +++ b/chrome/nsChromeRegistry.cpp @@ -592,6 +592,70 @@ nsChromeRegistry::AllowContentToAccess(nsIURI *aURI, bool *aResult) return NS_OK; } +NS_IMETHODIMP +nsChromeRegistry::CanLoadURLRemotely(nsIURI *aURI, bool *aResult) +{ + nsresult rv; + + *aResult = false; + +#ifdef DEBUG + bool isChrome; + aURI->SchemeIs("chrome", &isChrome); + NS_ASSERTION(isChrome, "Non-chrome URI passed to CanLoadURLRemotely!"); +#endif + + nsCOMPtr url = do_QueryInterface(aURI); + if (!url) { + NS_ERROR("Chrome URL doesn't implement nsIURL."); + return NS_ERROR_UNEXPECTED; + } + + nsAutoCString package; + rv = url->GetHostPort(package); + NS_ENSURE_SUCCESS(rv, rv); + + uint32_t flags; + rv = GetFlagsFromPackage(package, &flags); + + if (NS_SUCCEEDED(rv)) { + *aResult = !!(flags & REMOTE_ALLOWED); + } + return NS_OK; +} + +NS_IMETHODIMP +nsChromeRegistry::MustLoadURLRemotely(nsIURI *aURI, bool *aResult) +{ + nsresult rv; + + *aResult = false; + +#ifdef DEBUG + bool isChrome; + aURI->SchemeIs("chrome", &isChrome); + NS_ASSERTION(isChrome, "Non-chrome URI passed to MustLoadURLRemotely!"); +#endif + + nsCOMPtr url = do_QueryInterface(aURI); + if (!url) { + NS_ERROR("Chrome URL doesn't implement nsIURL."); + return NS_ERROR_UNEXPECTED; + } + + nsAutoCString package; + rv = url->GetHostPort(package); + NS_ENSURE_SUCCESS(rv, rv); + + uint32_t flags; + rv = GetFlagsFromPackage(package, &flags); + + if (NS_SUCCEEDED(rv)) { + *aResult = !!(flags & REMOTE_REQUIRED); + } + return NS_OK; +} + NS_IMETHODIMP_(bool) nsChromeRegistry::WrappersEnabled(nsIURI *aURI) { diff --git a/chrome/nsChromeRegistry.h b/chrome/nsChromeRegistry.h index 2908540413a..05edd006386 100644 --- a/chrome/nsChromeRegistry.h +++ b/chrome/nsChromeRegistry.h @@ -53,6 +53,10 @@ public: bool* _retval) MOZ_OVERRIDE; NS_IMETHOD AllowContentToAccess(nsIURI* url, bool* _retval) MOZ_OVERRIDE; + NS_IMETHOD CanLoadURLRemotely(nsIURI* url, + bool* _retval) MOZ_OVERRIDE; + NS_IMETHOD MustLoadURLRemotely(nsIURI* url, + bool* _retval) MOZ_OVERRIDE; // nsIChromeRegistry methods: NS_IMETHOD_(bool) WrappersEnabled(nsIURI *aURI) MOZ_OVERRIDE; @@ -120,26 +124,19 @@ public: }; virtual void ManifestContent(ManifestProcessingContext& cx, int lineno, - char *const * argv, bool platform, - bool contentaccessible) = 0; + char *const * argv, int flags) = 0; virtual void ManifestLocale(ManifestProcessingContext& cx, int lineno, - char *const * argv, bool platform, - bool contentaccessible) = 0; + char *const * argv, int flags) = 0; virtual void ManifestSkin(ManifestProcessingContext& cx, int lineno, - char *const * argv, bool platform, - bool contentaccessible) = 0; + char *const * argv, int flags) = 0; virtual void ManifestOverlay(ManifestProcessingContext& cx, int lineno, - char *const * argv, bool platform, - bool contentaccessible) = 0; + char *const * argv, int flags) = 0; virtual void ManifestStyle(ManifestProcessingContext& cx, int lineno, - char *const * argv, bool platform, - bool contentaccessible) = 0; + char *const * argv, int flags) = 0; virtual void ManifestOverride(ManifestProcessingContext& cx, int lineno, - char *const * argv, bool platform, - bool contentaccessible) = 0; + char *const * argv, int flags) = 0; virtual void ManifestResource(ManifestProcessingContext& cx, int lineno, - char *const * argv, bool platform, - bool contentaccessible) = 0; + char *const * argv, int flags) = 0; // Available flags enum { @@ -153,7 +150,13 @@ public: XPCNATIVEWRAPPERS = 1 << 1, // Content script may access files in this package - CONTENT_ACCESSIBLE = 1 << 2 + CONTENT_ACCESSIBLE = 1 << 2, + + // Package may be loaded remotely + REMOTE_ALLOWED = 1 << 3, + + // Package must be loaded remotely + REMOTE_REQUIRED = 1 << 4, }; bool mInitialized; diff --git a/chrome/nsChromeRegistryChrome.cpp b/chrome/nsChromeRegistryChrome.cpp index 15e077c8a16..935a01ff4c9 100644 --- a/chrome/nsChromeRegistryChrome.cpp +++ b/chrome/nsChromeRegistryChrome.cpp @@ -772,8 +772,7 @@ SendManifestEntry(const ChromeRegistryItem &aItem) void nsChromeRegistryChrome::ManifestContent(ManifestProcessingContext& cx, int lineno, - char *const * argv, bool platform, - bool contentaccessible) + char *const * argv, int flags) { char* package = argv[0]; char* uri = argv[1]; @@ -797,11 +796,7 @@ nsChromeRegistryChrome::ManifestContent(ManifestProcessingContext& cx, int linen nsDependentCString packageName(package); PackageEntry* entry = mPackagesHash.LookupOrAdd(packageName); entry->baseURI = resolved; - - if (platform) - entry->flags |= PLATFORM_PACKAGE; - if (contentaccessible) - entry->flags |= CONTENT_ACCESSIBLE; + entry->flags = flags; if (mDynamicRegistration) { ChromePackage chromePackage; @@ -813,8 +808,7 @@ nsChromeRegistryChrome::ManifestContent(ManifestProcessingContext& cx, int linen void nsChromeRegistryChrome::ManifestLocale(ManifestProcessingContext& cx, int lineno, - char *const * argv, bool platform, - bool contentaccessible) + char *const * argv, int flags) { char* package = argv[0]; char* provider = argv[1]; @@ -850,8 +844,7 @@ nsChromeRegistryChrome::ManifestLocale(ManifestProcessingContext& cx, int lineno void nsChromeRegistryChrome::ManifestSkin(ManifestProcessingContext& cx, int lineno, - char *const * argv, bool platform, - bool contentaccessible) + char *const * argv, int flags) { char* package = argv[0]; char* provider = argv[1]; @@ -887,8 +880,7 @@ nsChromeRegistryChrome::ManifestSkin(ManifestProcessingContext& cx, int lineno, void nsChromeRegistryChrome::ManifestOverlay(ManifestProcessingContext& cx, int lineno, - char *const * argv, bool platform, - bool contentaccessible) + char *const * argv, int flags) { char* base = argv[0]; char* overlay = argv[1]; @@ -915,8 +907,7 @@ nsChromeRegistryChrome::ManifestOverlay(ManifestProcessingContext& cx, int linen void nsChromeRegistryChrome::ManifestStyle(ManifestProcessingContext& cx, int lineno, - char *const * argv, bool platform, - bool contentaccessible) + char *const * argv, int flags) { char* base = argv[0]; char* overlay = argv[1]; @@ -943,8 +934,7 @@ nsChromeRegistryChrome::ManifestStyle(ManifestProcessingContext& cx, int lineno, void nsChromeRegistryChrome::ManifestOverride(ManifestProcessingContext& cx, int lineno, - char *const * argv, bool platform, - bool contentaccessible) + char *const * argv, int flags) { char* chrome = argv[0]; char* resolved = argv[1]; @@ -978,8 +968,7 @@ nsChromeRegistryChrome::ManifestOverride(ManifestProcessingContext& cx, int line void nsChromeRegistryChrome::ManifestResource(ManifestProcessingContext& cx, int lineno, - char *const * argv, bool platform, - bool contentaccessible) + char *const * argv, int flags) { char* package = argv[0]; char* uri = argv[1]; diff --git a/chrome/nsChromeRegistryChrome.h b/chrome/nsChromeRegistryChrome.h index 6d972d1955d..285b48a76f0 100644 --- a/chrome/nsChromeRegistryChrome.h +++ b/chrome/nsChromeRegistryChrome.h @@ -166,26 +166,19 @@ class nsChromeRegistryChrome : public nsChromeRegistry nsClassHashtable mPackagesHash; virtual void ManifestContent(ManifestProcessingContext& cx, int lineno, - char *const * argv, bool platform, - bool contentaccessible) MOZ_OVERRIDE; + char *const * argv, int flags) MOZ_OVERRIDE; virtual void ManifestLocale(ManifestProcessingContext& cx, int lineno, - char *const * argv, bool platform, - bool contentaccessible) MOZ_OVERRIDE; + char *const * argv, int flags) MOZ_OVERRIDE; virtual void ManifestSkin(ManifestProcessingContext& cx, int lineno, - char *const * argv, bool platform, - bool contentaccessible) MOZ_OVERRIDE; + char *const * argv, int flags) MOZ_OVERRIDE; virtual void ManifestOverlay(ManifestProcessingContext& cx, int lineno, - char *const * argv, bool platform, - bool contentaccessible) MOZ_OVERRIDE; + char *const * argv, int flags) MOZ_OVERRIDE; virtual void ManifestStyle(ManifestProcessingContext& cx, int lineno, - char *const * argv, bool platform, - bool contentaccessible) MOZ_OVERRIDE; + char *const * argv, int flags) MOZ_OVERRIDE; virtual void ManifestOverride(ManifestProcessingContext& cx, int lineno, - char *const * argv, bool platform, - bool contentaccessible) MOZ_OVERRIDE; + char *const * argv, int flags) MOZ_OVERRIDE; virtual void ManifestResource(ManifestProcessingContext& cx, int lineno, - char *const * argv, bool platform, - bool contentaccessible) MOZ_OVERRIDE; + char *const * argv, int flags) MOZ_OVERRIDE; }; #endif // nsChromeRegistryChrome_h diff --git a/chrome/nsChromeRegistryContent.cpp b/chrome/nsChromeRegistryContent.cpp index 3ea6f42ffcb..978b5f8aabf 100644 --- a/chrome/nsChromeRegistryContent.cpp +++ b/chrome/nsChromeRegistryContent.cpp @@ -257,7 +257,7 @@ nsresult nsChromeRegistryContent::UpdateSelectedLocale() void nsChromeRegistryContent::ManifestContent(ManifestProcessingContext& cx, int lineno, char *const * argv, - bool platform, bool contentaccessible) + int flags) { CONTENT_NOTREACHED(); } @@ -265,8 +265,7 @@ nsChromeRegistryContent::ManifestContent(ManifestProcessingContext& cx, void nsChromeRegistryContent::ManifestLocale(ManifestProcessingContext& cx, int lineno, - char *const * argv, bool platform, - bool contentaccessible) + char *const * argv, int flags) { CONTENT_NOTREACHED(); } @@ -274,16 +273,14 @@ nsChromeRegistryContent::ManifestLocale(ManifestProcessingContext& cx, void nsChromeRegistryContent::ManifestSkin(ManifestProcessingContext& cx, int lineno, - char *const * argv, bool platform, - bool contentaccessible) + char *const * argv, int flags) { CONTENT_NOTREACHED(); } void nsChromeRegistryContent::ManifestOverlay(ManifestProcessingContext& cx, int lineno, - char *const * argv, bool platform, - bool contentaccessible) + char *const * argv, int flags) { CONTENT_NOTREACHED(); } @@ -291,8 +288,7 @@ nsChromeRegistryContent::ManifestOverlay(ManifestProcessingContext& cx, int line void nsChromeRegistryContent::ManifestStyle(ManifestProcessingContext& cx, int lineno, - char *const * argv, bool platform, - bool contentaccessible) + char *const * argv, int flags) { CONTENT_NOTREACHED(); } @@ -300,8 +296,7 @@ nsChromeRegistryContent::ManifestStyle(ManifestProcessingContext& cx, void nsChromeRegistryContent::ManifestOverride(ManifestProcessingContext& cx, int lineno, - char *const * argv, bool platform, - bool contentaccessible) + char *const * argv, int flags) { CONTENT_NOTREACHED(); } @@ -309,8 +304,7 @@ nsChromeRegistryContent::ManifestOverride(ManifestProcessingContext& cx, void nsChromeRegistryContent::ManifestResource(ManifestProcessingContext& cx, int lineno, - char *const * argv, bool platform, - bool contentaccessible) + char *const * argv, int flags) { CONTENT_NOTREACHED(); } diff --git a/chrome/nsChromeRegistryContent.h b/chrome/nsChromeRegistryContent.h index 6f68a979e3d..5d88ae3a825 100644 --- a/chrome/nsChromeRegistryContent.h +++ b/chrome/nsChromeRegistryContent.h @@ -65,26 +65,19 @@ class nsChromeRegistryContent : public nsChromeRegistry nsCString mLocale; virtual void ManifestContent(ManifestProcessingContext& cx, int lineno, - char *const * argv, bool platform, - bool contentaccessible) MOZ_OVERRIDE; + char *const * argv, int flags) MOZ_OVERRIDE; virtual void ManifestLocale(ManifestProcessingContext& cx, int lineno, - char *const * argv, bool platform, - bool contentaccessible) MOZ_OVERRIDE; + char *const * argv, int flags) MOZ_OVERRIDE; virtual void ManifestSkin(ManifestProcessingContext& cx, int lineno, - char *const * argv, bool platform, - bool contentaccessible) MOZ_OVERRIDE; + char *const * argv, int flags) MOZ_OVERRIDE; virtual void ManifestOverlay(ManifestProcessingContext& cx, int lineno, - char *const * argv, bool platform, - bool contentaccessible) MOZ_OVERRIDE; + char *const * argv, int flags) MOZ_OVERRIDE; virtual void ManifestStyle(ManifestProcessingContext& cx, int lineno, - char *const * argv, bool platform, - bool contentaccessible) MOZ_OVERRIDE; + char *const * argv, int flags) MOZ_OVERRIDE; virtual void ManifestOverride(ManifestProcessingContext& cx, int lineno, - char *const * argv, bool platform, - bool contentaccessible) MOZ_OVERRIDE; + char *const * argv, int flags) MOZ_OVERRIDE; virtual void ManifestResource(ManifestProcessingContext& cx, int lineno, - char *const * argv, bool platform, - bool contentaccessible) MOZ_OVERRIDE; + char *const * argv, int flags) MOZ_OVERRIDE; }; #endif // nsChromeRegistryContent_h diff --git a/chrome/nsIChromeRegistry.idl b/chrome/nsIChromeRegistry.idl index c3c8cefc705..90e70f3ff58 100644 --- a/chrome/nsIChromeRegistry.idl +++ b/chrome/nsIChromeRegistry.idl @@ -45,7 +45,7 @@ interface nsIChromeRegistry : nsISupports [notxpcom] boolean wrappersEnabled(in nsIURI aURI); }; -[scriptable, uuid(c2461347-2b8f-48c7-9d59-3a61fb868828)] +[scriptable, uuid(93251ddf-5e85-4172-ac2a-31780562974f)] interface nsIXULChromeRegistry : nsIChromeRegistry { /* Should be called when locales change to reload all chrome (including XUL). */ @@ -73,6 +73,20 @@ interface nsIXULChromeRegistry : nsIChromeRegistry * Do not pass non-chrome URIs to this method. */ boolean allowContentToAccess(in nsIURI url); + + /** + * Returns true if the passed chrome URL is allowed to be loaded in a remote + * process. This reflects the remoteenabled flag on packages. + * Do not pass non-chrome URIs to this method. + */ + boolean canLoadURLRemotely(in nsIURI url); + + /** + * Returns true if the passed chrome URL must be loaded in a remote process. + * This reflects the remoterequired flag on packages. + * Do not pass non-chrome URIs to this method. + */ + boolean mustLoadURLRemotely(in nsIURI url); }; %{ C++ diff --git a/docshell/base/nsAboutRedirector.cpp b/docshell/base/nsAboutRedirector.cpp index b8c410ed8b6..96d9e57590a 100644 --- a/docshell/base/nsAboutRedirector.cpp +++ b/docshell/base/nsAboutRedirector.cpp @@ -49,6 +49,7 @@ static RedirEntry kRedirMap[] = { nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT }, { "neterror", "chrome://global/content/netError.xhtml", nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT | + nsIAboutModule::URI_CAN_LOAD_IN_CHILD | nsIAboutModule::ALLOW_SCRIPT | nsIAboutModule::HIDE_FROM_ABOUTABOUT }, { "memory", "chrome://global/content/aboutMemory.xhtml", diff --git a/netwerk/protocol/about/nsAboutBlank.cpp b/netwerk/protocol/about/nsAboutBlank.cpp index fd4d3b8ec9c..ea55b6326ad 100644 --- a/netwerk/protocol/about/nsAboutBlank.cpp +++ b/netwerk/protocol/about/nsAboutBlank.cpp @@ -55,6 +55,7 @@ NS_IMETHODIMP nsAboutBlank::GetURIFlags(nsIURI *aURI, uint32_t *result) { *result = nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT | + nsIAboutModule::URI_CAN_LOAD_IN_CHILD | nsIAboutModule::HIDE_FROM_ABOUTABOUT; return NS_OK; } diff --git a/netwerk/protocol/about/nsIAboutModule.idl b/netwerk/protocol/about/nsIAboutModule.idl index d2988e5e835..680a227ad2a 100644 --- a/netwerk/protocol/about/nsIAboutModule.idl +++ b/netwerk/protocol/about/nsIAboutModule.idl @@ -50,6 +50,16 @@ interface nsIAboutModule : nsISupports */ const unsigned long ENABLE_INDEXED_DB = (1 << 3); + /** + * A flag that indicates that this URI can be loaded in a child process + */ + const unsigned long URI_CAN_LOAD_IN_CHILD = (1 << 4); + + /** + * A flag that indicates that this URI must be loaded in a child process + */ + const unsigned long URI_MUST_LOAD_IN_CHILD = (1 << 5); + /** * A method to get the flags that apply to a given about: URI. The URI * passed in is guaranteed to be one of the URIs that this module diff --git a/testing/mochitest/runtests.py b/testing/mochitest/runtests.py index a077cce1194..44f066d565c 100644 --- a/testing/mochitest/runtests.py +++ b/testing/mochitest/runtests.py @@ -797,6 +797,8 @@ class MochitestUtilsMixin(object): # Register chrome directory. chrometestDir = self.getChromeTestDir(options) manifestFile.write("content mochitests %s contentaccessible=yes\n" % chrometestDir) + manifestFile.write("content mochitests-any %s contentaccessible=yes remoteenabled=yes\n" % chrometestDir) + manifestFile.write("content mochitests-content %s contentaccessible=yes remoterequired=yes\n" % chrometestDir) if options.testingModulesDir is not None: manifestFile.write("resource testing-common file:///%s\n" % diff --git a/xpcom/components/ManifestParser.cpp b/xpcom/components/ManifestParser.cpp index 526d401b4e2..4ca56f6a049 100644 --- a/xpcom/components/ManifestParser.cpp +++ b/xpcom/components/ManifestParser.cpp @@ -74,8 +74,7 @@ struct ManifestDirective int aLineNo, char* const* aArgv); void (nsChromeRegistry::*regfunc)( nsChromeRegistry::ManifestProcessingContext& aCx, - int aLineNo, char* const* aArgv, - bool aPlatform, bool aContentAccessible); + int aLineNo, char* const* aArgv, int aFlags); #ifdef MOZ_B2G_LOADER // The function to handle the directive for XPT Only parsing. void (*xptonlyfunc)( @@ -487,6 +486,8 @@ ParseManifest(NSLocationType aType, FileLocation& aFile, char* aBuf, NS_NAMED_LITERAL_STRING(kPlatform, "platform"); NS_NAMED_LITERAL_STRING(kContentAccessible, "contentaccessible"); + NS_NAMED_LITERAL_STRING(kRemoteEnabled, "remoteenabled"); + NS_NAMED_LITERAL_STRING(kRemoteRequired, "remoterequired"); NS_NAMED_LITERAL_STRING(kApplication, "application"); NS_NAMED_LITERAL_STRING(kAppVersion, "appversion"); NS_NAMED_LITERAL_STRING(kGeckoVersion, "platformversion"); @@ -684,8 +685,7 @@ ParseManifest(NSLocationType aType, FileLocation& aFile, char* aBuf, #if defined(MOZ_WIDGET_ANDROID) TriState stTablet = eUnspecified; #endif - bool platform = false; - bool contentAccessible = false; + int flags = 0; while ((token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) && ok) { @@ -710,10 +710,28 @@ ParseManifest(NSLocationType aType, FileLocation& aFile, char* aBuf, } #endif - if (directive->contentflags && - (CheckFlag(kPlatform, wtoken, platform) || - CheckFlag(kContentAccessible, wtoken, contentAccessible))) { - continue; + if (directive->contentflags) { + bool flag; + if (CheckFlag(kPlatform, wtoken, flag)) { + if (flag) + flags |= nsChromeRegistry::PLATFORM_PACKAGE; + continue; + } + if (CheckFlag(kContentAccessible, wtoken, flag)) { + if (flag) + flags |= nsChromeRegistry::CONTENT_ACCESSIBLE; + continue; + } + if (CheckFlag(kRemoteEnabled, wtoken, flag)) { + if (flag) + flags |= nsChromeRegistry::REMOTE_ALLOWED; + continue; + } + if (CheckFlag(kRemoteRequired, wtoken, flag)) { + if (flag) + flags |= nsChromeRegistry::REMOTE_REQUIRED; + continue; + } } bool xpcNativeWrappers = true; // Dummy for CheckFlag. @@ -765,7 +783,7 @@ ParseManifest(NSLocationType aType, FileLocation& aFile, char* aBuf, } (nsChromeRegistry::gChromeRegistry->*(directive->regfunc))( - chromecx, line, argv, platform, contentAccessible); + chromecx, line, argv, flags); } else if (directive->ischrome || !aChromeOnly) { if (directive->isContract) { CachedDirective* cd = contracts.AppendElement();