Skip to content

Commit

Permalink
Merge inbound to m-c a=merge
Browse files Browse the repository at this point in the history
MozReview-Commit-ID: AVhTkLAYIv7
  • Loading branch information
KWierso committed May 19, 2017
2 parents 1e6c284 + 9461e33 commit 0174ce8
Show file tree
Hide file tree
Showing 88 changed files with 2,344 additions and 1,063 deletions.
2 changes: 0 additions & 2 deletions browser/app/profile/firefox.js
Original file line number Diff line number Diff line change
Expand Up @@ -1282,8 +1282,6 @@ pref("pdfjs.previousHandler.alwaysAskBeforeHandling", false);
// (This is intentionally on the high side; see bug 746055.)
pref("image.mem.max_decoded_image_kb", 256000);

pref("social.sidebar.unload_timeout_ms", 10000);

// Activation from inside of share panel is possible if activationPanelEnabled
// is true. Pref'd off for release while usage testing is done through beta.
pref("social.share.activationPanelEnabled", true);
Expand Down
119 changes: 108 additions & 11 deletions browser/base/content/browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -996,6 +996,35 @@ function serializeInputStream(aStream) {
return data;
}

/**
* Handles URIs when we want to deal with them in chrome code rather than pass
* them down to a content browser. This can avoid unnecessary process switching
* for the browser.
* @param aBrowser the browser that is attempting to load the URI
* @param aUri the nsIURI that is being loaded
* @returns true if the URI is handled, otherwise false
*/
function handleUriInChrome(aBrowser, aUri) {
if (aUri.scheme == "file") {
try {
let mimeType = Cc["@mozilla.org/mime;1"].getService(Ci.nsIMIMEService)
.getTypeFromURI(aUri);
if (mimeType == "application/x-xpinstall") {
let systemPrincipal = Services.scriptSecurityManager.getSystemPrincipal();
AddonManager.getInstallForURL(aUri.spec, install => {
AddonManager.installAddonFromWebpage(mimeType, aBrowser, systemPrincipal,
install);
}, mimeType);
return true;
}
} catch (e) {
return false;
}
}

return false;
}

// A shared function used by both remote and non-remote browser XBL bindings to
// load a URI or redirect it to the correct process.
function _loadURIWithFlags(browser, uri, params) {
Expand All @@ -1016,8 +1045,33 @@ function _loadURIWithFlags(browser, uri, params) {
let postData = params.postData;

let currentRemoteType = browser.remoteType;
let requiredRemoteType =
E10SUtils.getRemoteTypeForURI(uri, gMultiProcessBrowser, currentRemoteType);
let requiredRemoteType;
try {
let fixupFlags = Ci.nsIURIFixup.FIXUP_FLAG_NONE;
if (flags & Ci.nsIWebNavigation.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) {
fixupFlags |= Ci.nsIURIFixup.FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP;
}
if (flags & Ci.nsIWebNavigation.LOAD_FLAGS_FIXUP_SCHEME_TYPOS) {
fixupFlags |= Ci.nsIURIFixup.FIXUP_FLAG_FIX_SCHEME_TYPOS;
}
let uriObject = Services.uriFixup.createFixupURI(uri, fixupFlags);
if (handleUriInChrome(browser, uriObject)) {
// If we've handled the URI in Chrome then just return here.
return;
}

// Note that I had thought that we could set uri = uriObject.spec here, to
// save on fixup later on, but that changes behavior and breaks tests.
requiredRemoteType =
E10SUtils.getRemoteTypeForURIObject(uriObject, gMultiProcessBrowser,
currentRemoteType, browser.currentURI);
} catch (e) {
// createFixupURI throws if it can't create a URI. If that's the case then
// we still need to pass down the uri because docshell handles this case.
requiredRemoteType = gMultiProcessBrowser ? E10SUtils.DEFAULT_REMOTE_TYPE
: E10SUtils.NOT_REMOTE;
}

let mustChangeProcess = requiredRemoteType != currentRemoteType;

// !requiredRemoteType means we're loading in the parent/this process.
Expand Down Expand Up @@ -1052,6 +1106,7 @@ function _loadURIWithFlags(browser, uri, params) {
flags,
referrer: referrer ? referrer.spec : null,
referrerPolicy,
remoteType: requiredRemoteType,
postData
}

Expand Down Expand Up @@ -1097,6 +1152,18 @@ function LoadInOtherProcess(browser, loadOptions, historyIndex = -1) {
// Called when a docshell has attempted to load a page in an incorrect process.
// This function is responsible for loading the page in the correct process.
function RedirectLoad({ target: browser, data }) {
if (data.loadOptions.reloadInFreshProcess) {
// Convert the fresh process load option into a large allocation remote type
// to use common processing from this point.
data.loadOptions.remoteType = E10SUtils.LARGE_ALLOCATION_REMOTE_TYPE;
data.loadOptions.newFrameloader = true;
} else if (browser.remoteType == E10SUtils.LARGE_ALLOCATION_REMOTE_TYPE) {
// If we're in a Large-Allocation process, we prefer switching back into a
// normal content process, as that way we can clean up the L-A process.
data.loadOptions.remoteType =
E10SUtils.getRemoteTypeForURI(data.loadOptions.uri, gMultiProcessBrowser);
}

// We should only start the redirection if the browser window has finished
// starting up. Otherwise, we should wait until the startup is done.
if (gBrowserInit.delayedStartupFinished) {
Expand Down Expand Up @@ -1136,17 +1203,47 @@ addEventListener("DOMContentLoaded", function onDCL() {
let initBrowser =
document.getAnonymousElementByAttribute(gBrowser, "anonid", "initialBrowser");

// The window's first argument is a tab if and only if we are swapping tabs.
// We must set the browser's usercontextid before updateBrowserRemoteness(),
// so that the newly created remote tab child has the correct usercontextid.
// remoteType and sameProcessAsFrameLoader are passed through to
// updateBrowserRemoteness as part of an options object, which itself defaults
// to an empty object. So defaulting them to undefined here will cause the
// default behavior in updateBrowserRemoteness if they don't get set.
let isRemote = gMultiProcessBrowser;
let remoteType;
let sameProcessAsFrameLoader;
if (window.arguments) {
let tabToOpen = window.arguments[0];
if (tabToOpen instanceof XULElement && tabToOpen.hasAttribute("usercontextid")) {
initBrowser.setAttribute("usercontextid", tabToOpen.getAttribute("usercontextid"));
}
}
let argToLoad = window.arguments[0];
if (argToLoad instanceof XULElement) {
// The window's first argument is a tab if and only if we are swapping tabs.
// We must set the browser's usercontextid before updateBrowserRemoteness(),
// so that the newly created remote tab child has the correct usercontextid.
if (argToLoad.hasAttribute("usercontextid")) {
initBrowser.setAttribute("usercontextid",
argToLoad.getAttribute("usercontextid"));
}

gBrowser.updateBrowserRemoteness(initBrowser, gMultiProcessBrowser);
let linkedBrowser = argToLoad.linkedBrowser;
if (linkedBrowser) {
remoteType = linkedBrowser.remoteType;
isRemote = remoteType != E10SUtils.NOT_REMOTE;
sameProcessAsFrameLoader = linkedBrowser.frameLoader;
}
} else if (argToLoad instanceof String) {
// argToLoad is String, so should be a URL.
remoteType = E10SUtils.getRemoteTypeForURI(argToLoad, gMultiProcessBrowser);
isRemote = remoteType != E10SUtils.NOT_REMOTE;
} else if (argToLoad instanceof Ci.nsIArray) {
// argToLoad is nsIArray, so should be an array of URLs, set the remote
// type for the initial browser to match the first one.
let urisstring = argToLoad.queryElementAt(0, Ci.nsISupportsString);
remoteType = E10SUtils.getRemoteTypeForURI(urisstring.data,
gMultiProcessBrowser);
isRemote = remoteType != E10SUtils.NOT_REMOTE;
}
}

gBrowser.updateBrowserRemoteness(initBrowser, isRemote, {
remoteType, sameProcessAsFrameLoader
});
});

let _resolveDelayedStartup;
Expand Down
38 changes: 16 additions & 22 deletions browser/base/content/tabbrowser.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1753,10 +1753,13 @@
}
// NB: This works with the hack in the browser constructor that
// turns this normal property into a field. When switching remote
// type copying related browser would stop the switch and the
// previously related browser will no longer be relevant.
if (!aShouldBeRemote || currentRemoteType == aOptions.remoteType) {
// turns this normal property into a field.
if (aOptions.sameProcessAsFrameLoader) {
// Always set sameProcessAsFrameLoader when passed in aOptions.
aBrowser.sameProcessAsFrameLoader = aOptions.sameProcessAsFrameLoader;
} else if (!aShouldBeRemote || currentRemoteType == aOptions.remoteType) {
// Only copy existing sameProcessAsFrameLoader when not switching
// remote type otherwise it would stop the switch.
aBrowser.sameProcessAsFrameLoader = sameProcessAsFrameLoader;
}
Expand Down Expand Up @@ -1841,20 +1844,13 @@
if (!gMultiProcessBrowser)
return this.updateBrowserRemoteness(aBrowser, false);
// If we're in a LargeAllocation process, we prefer switching back
// into a normal content process, as that way we can clean up the
// L-A process.
let currentRemoteType = aBrowser.getAttribute("remoteType") || null;
let preferredRemoteType = currentRemoteType;
if (currentRemoteType == E10SUtils.LARGE_ALLOCATION_REMOTE_TYPE) {
preferredRemoteType = E10SUtils.DEFAULT_REMOTE_TYPE;
}
aOptions.remoteType =
E10SUtils.getRemoteTypeForURI(aURL,
gMultiProcessBrowser,
preferredRemoteType,
aOptions.freshProcess);
currentRemoteType,
aBrowser.currentURI);
// If this URL can't load in the current browser then flip it to the
// correct type.
Expand Down Expand Up @@ -3604,21 +3600,19 @@
<![CDATA[
// Swap the dropped tab with a new one we create and then close
// it in the other window (making it seem to have moved between
// windows).
let params = { eventDetail: { adoptedTab: aTab } };
// windows). We also ensure that the tab we create to swap into has
// the same remote type and process as the one we're swapping in.
// This makes sure we don't get a short-lived process for the new tab.
let linkedBrowser = aTab.linkedBrowser;
let params = { eventDetail: { adoptedTab: aTab },
preferredRemoteType: linkedBrowser.remoteType,
sameProcessAsFrameLoader: linkedBrowser.frameLoader };
if (aTab.hasAttribute("usercontextid")) {
// new tab must have the same usercontextid as the old one
params.userContextId = aTab.getAttribute("usercontextid");
}
let newTab = this.addTab("about:blank", params);
let newBrowser = this.getBrowserForTab(newTab);
let newURL = aTab.linkedBrowser.currentURI.spec;
// If we're an e10s browser window, an exception will be thrown
// if we attempt to drag a non-remote browser in, so we need to
// ensure that the remoteness of the newly created browser is
// appropriate for the URL of the tab being dragged in.
this.updateBrowserRemotenessByURL(newBrowser, newURL);
// Stop the about:blank load.
newBrowser.stop();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,19 @@

const TEST_FILE = "dummy_page.html";
const TEST_HTTP = "http://example.org/";
const TEST_CROSS_ORIGIN = "http://example.com/";

function CheckBrowserInPid(browser, expectedPid, message) {
return ContentTask.spawn(browser, { expectedPid, message }, (arg) => {
is(Services.appinfo.processID, arg.expectedPid, arg.message);
});
}

function CheckBrowserNotInPid(browser, unExpectedPid, message) {
return ContentTask.spawn(browser, { unExpectedPid, message }, (arg) => {
isnot(Services.appinfo.processID, arg.unExpectedPid, arg.message);
});
}

// Test for bug 1343184.
add_task(async function() {
Expand All @@ -11,29 +24,115 @@ add_task(async function() {
dir.append(TEST_FILE);
const uriString = Services.io.newFileURI(dir).spec;
await BrowserTestUtils.withNewTab(uriString, async function(fileBrowser) {
// Set prefs to ensure file content process and to allow linked web content
// in file URI process.
// Set prefs to ensure file content process, to allow linked web content
// in file URI process and allow more that one file content process.
await SpecialPowers.pushPrefEnv(
{set: [["browser.tabs.remote.separateFileUriProcess", true],
["browser.tabs.remote.allowLinkedWebInFileUriProcess", true]]});
["browser.tabs.remote.allowLinkedWebInFileUriProcess", true],
["dom.ipc.processCount.file", 2]]});

// Get the file:// URI pid for comparison later.
let filePid = await ContentTask.spawn(fileBrowser, null, () => {
return Services.appinfo.processID;
});

// Open new http tab from JavaScript in file:// page.
let promiseTabOpened = BrowserTestUtils.waitForNewTab(gBrowser, TEST_HTTP);
// Check that http tab opened from JS in file:// page is in same process.
let promiseTabOpened = BrowserTestUtils.waitForNewTab(gBrowser, TEST_HTTP, true);
await ContentTask.spawn(fileBrowser, TEST_HTTP, uri => {
content.open(uri, "_blank");
});
let httpTab = await promiseTabOpened;
let httpBrowser = httpTab.linkedBrowser;
registerCleanupFunction(async function() {
await BrowserTestUtils.removeTab(httpTab);
});
await CheckBrowserInPid(httpBrowser, filePid,
"Check that new http tab opened from file loaded in file content process.");

// Ensure that http browser is running in the same process as the file:// one.
let filePid = await ContentTask.spawn(fileBrowser, null, () => {
return Services.appinfo.processID;
// Check that reload doesn't break the file content process affinity.
if (httpTab != gBrowser.selectedTab) {
httpTab = await BrowserTestUtils.switchTab(gBrowser, httpTab);
httpBrowser = httpTab.linkedBrowser;
}
let promiseLoad = BrowserTestUtils.browserLoaded(httpBrowser);
document.getElementById("reload-button").doCommand();
await promiseLoad;
await CheckBrowserInPid(httpBrowser, filePid,
"Check that http tab still in file content process after reload.");

// Check that same-origin load doesn't break the affinity.
promiseLoad = BrowserTestUtils.browserLoaded(httpBrowser);
httpBrowser.loadURI(TEST_HTTP + "foo");
await promiseLoad;
await CheckBrowserInPid(httpBrowser, filePid,
"Check that http tab still in file content process after same origin load.");

// Check that history back doesn't break the affinity.
let promiseLocation =
BrowserTestUtils.waitForLocationChange(gBrowser, TEST_HTTP);
httpBrowser.goBack();
await promiseLocation;
await CheckBrowserInPid(httpBrowser, filePid,
"Check that http tab still in file content process after history back.");

// Check that history forward doesn't break the affinity.
promiseLocation =
BrowserTestUtils.waitForLocationChange(gBrowser, TEST_HTTP + "foo");
promiseLoad = BrowserTestUtils.browserLoaded(httpBrowser);
httpBrowser.goForward();
await promiseLocation;
await CheckBrowserInPid(httpBrowser, filePid,
"Check that http tab still in file content process after history forward.");

// Check that goto history index doesn't break the affinity.
promiseLocation = BrowserTestUtils.waitForLocationChange(gBrowser, TEST_HTTP);
httpBrowser.gotoIndex(0);
await promiseLocation;
await CheckBrowserInPid(httpBrowser, filePid,
"Check that http tab still in file content process after history gotoIndex.");

// Check that file:// URI load doesn't break the affinity.
promiseLoad = BrowserTestUtils.browserLoaded(httpBrowser);
httpBrowser.loadURI(uriString);
await promiseLoad;
await CheckBrowserInPid(httpBrowser, filePid,
"Check that http tab still in file content process after file:// load.");

// Check that location change doesn't break the affinity.
promiseLoad = BrowserTestUtils.browserLoaded(httpBrowser);
await ContentTask.spawn(httpBrowser, TEST_HTTP, uri => {
content.location = uri;
});
await ContentTask.spawn(httpTab.linkedBrowser, filePid, (expectedPid) => {
is(Services.appinfo.processID, expectedPid,
"Check that new http page opened from file loaded in file content process.");
await promiseLoad;
await CheckBrowserInPid(httpBrowser, filePid,
"Check that http tab still in file content process after location change.");

// Check that cross-origin load does break the affinity.
promiseLoad = BrowserTestUtils.browserLoaded(httpBrowser);
httpBrowser.loadURI(TEST_CROSS_ORIGIN);
await promiseLoad;
await CheckBrowserNotInPid(httpBrowser, filePid,
"Check that http tab not in file content process after cross origin load.");
is(httpBrowser.remoteType, E10SUtils.WEB_REMOTE_TYPE,
"Check that tab now has web remote type.");

// Check that history back now remains in the web content process.
let httpPid = await ContentTask.spawn(httpBrowser, null, () => {
return Services.appinfo.processID;
});
promiseLocation = BrowserTestUtils.waitForLocationChange(gBrowser, TEST_HTTP);
httpBrowser.goBack();
await promiseLocation;
await CheckBrowserInPid(httpBrowser, httpPid,
"Check that http tab still in web content process after process switch and history back.");

// Check that history back to file:// URI switches to file content process.
promiseLocation = BrowserTestUtils.waitForLocationChange(gBrowser, uriString);
httpBrowser.goBack();
await promiseLocation;
await CheckBrowserNotInPid(httpBrowser, httpPid,
"Check that history back to file:// URI switches to file content process.");
is(httpBrowser.remoteType, E10SUtils.FILE_REMOTE_TYPE,
"Check that tab now has file remote type.");
});
});
Loading

0 comments on commit 0174ce8

Please sign in to comment.