Bug 1075658: Make browser.loadURI synchronously update the browser remoteness. r=ttaubert

This commit is contained in:
Dave Townsend 2014-10-29 13:26:14 -07:00
parent f315b9c8f0
commit 6a2be7b874
14 changed files with 235 additions and 89 deletions

View File

@ -22,8 +22,12 @@ searchbar {
-moz-binding: url("chrome://browser/content/search/search.xml#searchbar");
}
.browserStack > browser {
-moz-binding: url("chrome://browser/content/tabbrowser.xml#tabbrowser-browser");
}
.browserStack > browser[remote="true"] {
-moz-binding: url("chrome://global/content/bindings/remote-browser.xml#remote-browser");
-moz-binding: url("chrome://browser/content/tabbrowser.xml#tabbrowser-remote-browser");
}
toolbar[customizable="true"] {

View File

@ -799,34 +799,62 @@ function gKeywordURIFixup({ target: browser, data: fixupInfo }) {
}
}
// 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 }) {
// 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, flags, referrer, charset, postdata) {
if (!uri) {
uri = "about:blank";
}
if (!(flags & browser.webNavigation.LOAD_FLAGS_FROM_EXTERNAL)) {
browser.userTypedClear++;
}
try {
let shouldBeRemote = gMultiProcessBrowser &&
E10SUtils.shouldBrowserBeRemote(uri);
if (browser.isRemoteBrowser == shouldBeRemote) {
browser.webNavigation.loadURI(uri, flags, referrer, postdata, null);
} else {
LoadInOtherProcess(browser, {
uri: uri,
flags: flags,
referrer: referrer ? referrer.spec : null,
});
}
} finally {
if (browser.userTypedClear) {
browser.userTypedClear--;
}
}
}
// Starts a new load in the browser first switching the browser to the correct
// process
function LoadInOtherProcess(browser, loadOptions, historyIndex = -1) {
let tab = gBrowser.getTabForBrowser(browser);
// Flush the tab state before getting it
TabState.flush(browser);
let tabState = JSON.parse(SessionStore.getTabState(tab));
if (data.historyIndex < 0) {
// Add a pseudo-history state for the new url to load
let newEntry = {
url: data.uri,
referrer: data.referrer,
};
tabState.entries = tabState.entries.slice(0, tabState.index);
tabState.entries.push(newEntry);
tabState.index++;
if (historyIndex < 0) {
tabState.userTypedValue = null;
// Tell session history the new page to load
SessionStore._restoreTabAndLoad(tab, JSON.stringify(tabState), loadOptions);
}
else {
// Update the history state to point to the requested index
tabState.index = data.historyIndex + 1;
tabState.index = historyIndex + 1;
// SessionStore takes care of setting the browser remoteness before restoring
// history into it.
SessionStore.setTabState(tab, JSON.stringify(tabState));
}
}
// SessionStore takes care of setting the browser remoteness before restoring
// history into it.
SessionStore.setTabState(tab, JSON.stringify(tabState));
// 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 }) {
LoadInOtherProcess(browser, data.loadOptions, data.historyIndex);
}
var gBrowserInit = {

View File

@ -5377,4 +5377,42 @@
</implementation>
</binding>
<binding id="tabbrowser-browser"
extends="chrome://global/content/bindings/browser.xml#browser">
<implementation>
<!-- throws exception for unknown schemes -->
<method name="loadURIWithFlags">
<parameter name="aURI"/>
<parameter name="aFlags"/>
<parameter name="aReferrerURI"/>
<parameter name="aCharset"/>
<parameter name="aPostData"/>
<body>
<![CDATA[
_loadURIWithFlags(this, aURI, aFlags, aReferrerURI, aCharset, aPostData);
]]>
</body>
</method>
</implementation>
</binding>
<binding id="tabbrowser-remote-browser"
extends="chrome://global/content/bindings/remote-browser.xml#remote-browser">
<implementation>
<!-- throws exception for unknown schemes -->
<method name="loadURIWithFlags">
<parameter name="aURI"/>
<parameter name="aFlags"/>
<parameter name="aReferrerURI"/>
<parameter name="aCharset"/>
<parameter name="aPostData"/>
<body>
<![CDATA[
_loadURIWithFlags(this, aURI, aFlags, aReferrerURI, aCharset, aPostData);
]]>
</body>
</method>
</implementation>
</binding>
</bindings>

View File

@ -231,7 +231,6 @@ skip-if = e10s # Bug ?????? - test directly manipulates content
[browser_bug579872.js]
[browser_bug580638.js]
[browser_bug580956.js]
skip-if = e10s # Bug 516755 - SessionStore disabled for e10s
[browser_bug581242.js]
skip-if = e10s # Bug 930863 - pageshow issues ("TypeError: charset is undefined" in pageshow listener, as document is null)
[browser_bug581253.js]
@ -254,7 +253,6 @@ skip-if = e10s # Bug 516755 - SessionStore disabled for e10s (calls duplicateTab
[browser_bug623155.js]
skip-if = e10s # Bug ?????? - URLBar issues (apparently issues with redirection)
[browser_bug623893.js]
skip-if = e10s # Bug 916974 - Session history doesn't work in e10s
[browser_bug624734.js]
[browser_bug633691.js]
skip-if = e10s # Bug ?????? - test directly manipulates content (eg, var expertDiv = gBrowser.contentDocument.getElementById("expertContent");)
@ -272,6 +270,7 @@ skip-if = e10s # Bug ?????? - test directly manipulates content (doc.querySelect
[browser_bug719271.js]
skip-if = e10s # Bug 691614 - no e10s zoom support yet
[browser_bug724239.js]
skip-if = e10s # Bug 1077738
[browser_bug734076.js]
skip-if = e10s # Bug ?????? - test directly manipulates content
[browser_bug735471.js]
@ -287,7 +286,6 @@ skip-if = e10s # Bug ?????? - test directly manipulates content
[browser_bug816527.js]
skip-if = e10s # Bug 916974 - Session history doesn't work in e10s
[browser_bug817947.js]
skip-if = e10s # Bug 916974 - Session history doesn't work in e10s
[browser_bug822367.js]
[browser_bug832435.js]
[browser_bug839103.js]
@ -494,7 +492,6 @@ skip-if = e10s # Bug 516755 - SessionStore disabled for e10s
[browser_registerProtocolHandler_notification.js]
skip-if = e10s # Bug 940206 - nsIWebContentHandlerRegistrar::registerProtocolHandler doesn't work in e10s
[browser_no_mcb_on_http_site.js]
skip-if = e10s # Bug 516755 - SessionStore disabled for e10s
[browser_bug1003461-switchtab-override.js]
skip-if = e10s
[browser_bug1024133-switchtab-override-keynav.js]

View File

@ -52,7 +52,8 @@ let check_history = Task.async(function*() {
// Waits for a load and updates the known history
let waitForLoad = Task.async(function*(uri) {
info("Loading " + uri);
gBrowser.loadURI(uri);
// Longwinded but this ensures we don't just shortcut to LoadInNewProcess
gBrowser.selectedBrowser.webNavigation.loadURI(uri, Ci.nsIWebNavigation.LOAD_FLAGS_NONE, null, null, null);
yield waitForDocLoadComplete();
gExpectedHistory.index++;
@ -78,7 +79,7 @@ let forward = Task.async(function*() {
// Tests that navigating from a page that should be in the remote process and
// a page that should be in the main process works and retains history
add_task(function*() {
add_task(function* test_navigation() {
SimpleTest.requestCompleteLog();
let remoting = Services.prefs.getBoolPref("browser.tabs.remote.autostart");
@ -138,5 +139,59 @@ add_task(function*() {
yield check_history();
info("9");
yield back();
is(gBrowser.selectedTab.getAttribute("remote"), "", "Remote attribute should be correct");
is(gBrowser.selectedBrowser.permanentKey, permanentKey, "browser.permanentKey is still the same");
yield check_history();
info("10");
// Load a new remote page, this should replace the last history entry
gExpectedHistory.entries.splice(gExpectedHistory.entries.length - 1, 1);
yield waitForLoad("http://example.com/" + DUMMY_PATH);
is(gBrowser.selectedTab.getAttribute("remote"), expectedRemote, "Remote attribute should be correct");
is(gBrowser.selectedBrowser.permanentKey, permanentKey, "browser.permanentKey is still the same");
yield check_history();
info("11");
gBrowser.removeCurrentTab();
});
// Tests that calling gBrowser.loadURI or browser.loadURI to load a page in a
// different process updates the browser synchronously
add_task(function* test_synchronous() {
let remoting = Services.prefs.getBoolPref("browser.tabs.remote.autostart");
let expectedRemote = remoting ? "true" : "";
info("1");
// Create a tab and load a remote page in it
gBrowser.selectedTab = gBrowser.addTab("about:blank", {skipAnimation: true});
let {permanentKey} = gBrowser.selectedBrowser;
yield waitForLoad("http://example.org/" + DUMMY_PATH);
is(gBrowser.selectedTab.getAttribute("remote"), expectedRemote, "Remote attribute should be correct");
is(gBrowser.selectedBrowser.permanentKey, permanentKey, "browser.permanentKey is still the same");
info("2");
// Load another page
info("Loading about:robots");
gBrowser.selectedBrowser.loadURI("about:robots");
is(gBrowser.selectedTab.getAttribute("remote"), "", "Remote attribute should be correct");
is(gBrowser.selectedBrowser.permanentKey, permanentKey, "browser.permanentKey is still the same");
yield waitForDocLoadComplete();
is(gBrowser.selectedTab.getAttribute("remote"), "", "Remote attribute should be correct");
is(gBrowser.selectedBrowser.permanentKey, permanentKey, "browser.permanentKey is still the same");
info("3");
// Load the remote page again
info("Loading http://example.org/" + DUMMY_PATH);
gBrowser.loadURI("http://example.org/" + DUMMY_PATH);
is(gBrowser.selectedTab.getAttribute("remote"), expectedRemote, "Remote attribute should be correct");
is(gBrowser.selectedBrowser.permanentKey, permanentKey, "browser.permanentKey is still the same");
yield waitForDocLoadComplete();
is(gBrowser.selectedTab.getAttribute("remote"), expectedRemote, "Remote attribute should be correct");
is(gBrowser.selectedBrowser.permanentKey, permanentKey, "browser.permanentKey is still the same");
info("4");
gBrowser.removeCurrentTab();
});

View File

@ -159,7 +159,7 @@ ContentRestoreInternal.prototype = {
* Start loading the current page. When the data has finished loading from the
* network, finishCallback is called. Returns true if the load was successful.
*/
restoreTabContent: function (finishCallback) {
restoreTabContent: function (loadArguments, finishCallback) {
let tabData = this._tabData;
this._tabData = null;
@ -188,7 +188,19 @@ ContentRestoreInternal.prototype = {
webNavigation.setCurrentURI(Utils.makeURI("about:blank"));
try {
if (tabData.userTypedValue && tabData.userTypedClear) {
if (loadArguments) {
// A load has been redirected to a new process so get history into the
// same state it was before the load started then trigger the load.
let activeIndex = tabData.index - 1;
if (activeIndex > 0) {
// Go to the right history entry, but don't load anything yet.
history.getEntryAtIndex(activeIndex, true);
}
let referrer = loadArguments.referrer ?
Utils.makeURI(loadArguments.referrer) : null;
webNavigation.loadURI(loadArguments.uri, loadArguments.loadFlags,
referrer, null, null);
} else if (tabData.userTypedValue && tabData.userTypedClear) {
// If the user typed a URL into the URL bar and hit enter right before
// we crashed, we want to start loading that page again. A non-zero
// userTypedClear value means that the load had started.

View File

@ -192,6 +192,16 @@ this.SessionStore = {
SessionStoreInternal.setTabState(aTab, aState);
},
// This should not be used by external code, the intention is to remove it
// once a better fix is in place for process switching in e10s.
// See bug 1075658 for context.
_restoreTabAndLoad: function ss_restoreTabAndLoad(aTab, aState, aLoadArguments) {
SessionStoreInternal.setTabState(aTab, aState, {
restoreImmediately: true,
loadArguments: aLoadArguments
});
},
duplicateTab: function ss_duplicateTab(aWindow, aTab, aDelta = 0) {
return SessionStoreInternal.duplicateTab(aWindow, aTab, aDelta);
},
@ -1572,7 +1582,7 @@ let SessionStoreInternal = {
return this._toJSONString(tabState);
},
setTabState: function ssi_setTabState(aTab, aState) {
setTabState: function ssi_setTabState(aTab, aState, aOptions) {
// Remove the tab state from the cache.
// Note that we cannot simply replace the contents of the cache
// as |aState| can be an incomplete state that will be completed
@ -1597,7 +1607,7 @@ let SessionStoreInternal = {
this._resetTabRestoringState(aTab);
}
this.restoreTab(aTab, tabState);
this.restoreTab(aTab, tabState, aOptions);
},
duplicateTab: function ssi_duplicateTab(aWindow, aTab, aDelta = 0) {
@ -1623,7 +1633,9 @@ let SessionStoreInternal = {
aWindow.gBrowser.addTab(null, {relatedToCurrent: true, ownerTab: aTab}) :
aWindow.gBrowser.addTab();
this.restoreTab(newTab, tabState, true /* Load this tab right away. */);
this.restoreTab(newTab, tabState, {
restoreImmediately: true /* Load this tab right away. */
});
return newTab;
},
@ -2527,7 +2539,9 @@ let SessionStoreInternal = {
},
// Restores the given tab state for a given tab.
restoreTab(tab, tabData, restoreImmediately = false) {
restoreTab(tab, tabData, options = {}) {
let restoreImmediately = options.restoreImmediately;
let loadArguments = options.loadArguments;
let browser = tab.linkedBrowser;
let window = tab.ownerDocument.defaultView;
let tabbrowser = window.gBrowser;
@ -2595,6 +2609,9 @@ let SessionStoreInternal = {
// attribute so that it runs in a content process.
let activePageData = tabData.entries[activeIndex] || null;
let uri = activePageData ? activePageData.url || null : null;
if (loadArguments) {
uri = loadArguments.uri;
}
tabbrowser.updateBrowserRemotenessByURL(browser, uri);
// Start a new epoch and include the epoch in the restoreHistory
@ -2630,8 +2647,8 @@ let SessionStoreInternal = {
// This could cause us to ignore MAX_CONCURRENT_TAB_RESTORES a bit, but
// it ensures each window will have its selected tab loaded.
if (restoreImmediately || tabbrowser.selectedBrowser == browser) {
this.restoreTabContent(tab);
if (restoreImmediately || tabbrowser.selectedBrowser == browser || loadArguments) {
this.restoreTabContent(tab, loadArguments);
} else {
TabRestoreQueue.add(tab);
this.restoreNextTab();
@ -2658,7 +2675,7 @@ let SessionStoreInternal = {
*
* @returns true/false indicating whether or not a load actually happened
*/
restoreTabContent: function (aTab) {
restoreTabContent: function (aTab, aLoadArguments = null) {
let window = aTab.ownerDocument.defaultView;
let browser = aTab.linkedBrowser;
let tabData = browser.__SS_data;
@ -2687,7 +2704,8 @@ let SessionStoreInternal = {
browser.__SS_restore_tab = aTab;
browser.messageManager.sendAsyncMessage("SessionStore:restoreTabContent");
browser.messageManager.sendAsyncMessage("SessionStore:restoreTabContent",
{loadArguments: aLoadArguments});
},
/**

View File

@ -145,7 +145,7 @@ let MessageListener = {
};
// We need to pass the value of didStartLoad back to SessionStore.jsm.
let didStartLoad = gContentRestore.restoreTabContent(finishCallback);
let didStartLoad = gContentRestore.restoreTabContent(data.loadArguments, finishCallback);
sendAsyncMessage("SessionStore:restoreTabContentStarted", {epoch: epoch});

View File

@ -66,7 +66,6 @@ support-files =
[browser_capabilities.js]
[browser_cleaner.js]
[browser_dying_cache.js]
skip-if = e10s
[browser_dynamic_frames.js]
[browser_form_restore_events.js]
[browser_formdata.js]
@ -83,13 +82,12 @@ skip-if = buildapp == 'mulet'
[browser_privatetabs.js]
[browser_scrollPositions.js]
[browser_sessionHistory.js]
# Disabled because of bug 1077581
skip-if = e10s
[browser_sessionStorage.js]
skip-if = e10s
[browser_swapDocShells.js]
skip-if = e10s # See bug 918634
[browser_telemetry.js]
skip-if = e10s
[browser_upgrade_backup.js]
[browser_windowRestore_perwindowpb.js]
[browser_248970_b_perwindowpb.js]
@ -107,10 +105,8 @@ skip-if = true
skip-if = true
[browser_394759_behavior.js]
[browser_394759_perwindowpb.js]
skip-if = e10s
[browser_394759_purge.js]
[browser_423132.js]
skip-if = e10s
[browser_447951.js]
[browser_454908.js]
[browser_456342.js]
@ -124,7 +120,6 @@ skip-if = e10s
[browser_467409-backslashplosion.js]
[browser_477657.js]
[browser_480893.js]
skip-if = e10s
[browser_485482.js]
[browser_485563.js]
[browser_490040.js]
@ -197,6 +192,6 @@ skip-if = true
# Disabled on OS X:
[browser_625016.js]
skip-if = os == "mac" || e10s
skip-if = os == "mac"
[browser_911547.js]

View File

@ -25,48 +25,51 @@ function test() {
newWin.addEventListener("load", function (aEvent) {
newWin.removeEventListener("load", arguments.callee, false);
newWin.gBrowser.loadURI(testURL, null, null);
// Wait for sessionstore to be ready to restore this window
executeSoon(function() {
newWin.gBrowser.loadURI(testURL, null, null);
whenBrowserLoaded(newWin.gBrowser.selectedBrowser, function() {
// get the sessionstore state for the window
TabState.flush(newWin.gBrowser.selectedBrowser);
let state = ss.getWindowState(newWin);
whenBrowserLoaded(newWin.gBrowser.selectedBrowser, function() {
// get the sessionstore state for the window
TabState.flush(newWin.gBrowser.selectedBrowser);
let state = ss.getWindowState(newWin);
// verify our cookie got set during pageload
let e = cs.enumerator;
let cookie;
let i = 0;
while (e.hasMoreElements()) {
cookie = e.getNext().QueryInterface(Ci.nsICookie);
i++;
}
is(i, 1, "expected one cookie");
// verify our cookie got set during pageload
let e = cs.enumerator;
let cookie;
let i = 0;
while (e.hasMoreElements()) {
cookie = e.getNext().QueryInterface(Ci.nsICookie);
i++;
}
is(i, 1, "expected one cookie");
// remove the cookie
cs.removeAll();
// remove the cookie
cs.removeAll();
// restore the window state
ss.setWindowState(newWin, state, true);
// restore the window state
ss.setWindowState(newWin, state, true);
// at this point, the cookie should be restored...
e = cs.enumerator;
let cookie2;
while (e.hasMoreElements()) {
cookie2 = e.getNext().QueryInterface(Ci.nsICookie);
if (cookie.name == cookie2.name)
break;
}
is(cookie.name, cookie2.name, "cookie name successfully restored");
is(cookie.value, cookie2.value, "cookie value successfully restored");
is(cookie.path, cookie2.path, "cookie path successfully restored");
// at this point, the cookie should be restored...
e = cs.enumerator;
let cookie2;
while (e.hasMoreElements()) {
cookie2 = e.getNext().QueryInterface(Ci.nsICookie);
if (cookie.name == cookie2.name)
break;
}
is(cookie.name, cookie2.name, "cookie name successfully restored");
is(cookie.value, cookie2.value, "cookie value successfully restored");
is(cookie.path, cookie2.path, "cookie path successfully restored");
// clean up
if (gPrefService.prefHasUserValue("browser.sessionstore.interval"))
gPrefService.clearUserPref("browser.sessionstore.interval");
cs.removeAll();
newWin.close();
finish();
}, true, testURL);
// clean up
if (gPrefService.prefHasUserValue("browser.sessionstore.interval"))
gPrefService.clearUserPref("browser.sessionstore.interval");
cs.removeAll();
newWin.close();
finish();
}, true, testURL);
});
}, false);
}

View File

@ -175,9 +175,9 @@ function testOnWindow(aIsPrivate, aCallback) {
function waitForTabLoad(aWin, aURL, aCallback) {
let browser = aWin.gBrowser.selectedBrowser;
browser.loadURI(aURL);
whenBrowserLoaded(browser, function () {
TabState.flush(browser);
executeSoon(aCallback);
});
browser.loadURI(aURL);
}

View File

@ -17,6 +17,7 @@ support-files =
[browser_tabview_bug587231.js]
skip-if = buildapp == 'mulet'
[browser_tabview_bug587276.js]
skip-if = e10s # Bug 1091200
[browser_tabview_bug587351.js]
[browser_tabview_bug587503.js]
[browser_tabview_bug587990.js]

View File

@ -51,8 +51,11 @@ this.E10SUtils = {
let sessionHistory = aDocShell.getInterface(Ci.nsIWebNavigation).sessionHistory;
messageManager.sendAsyncMessage("Browser:LoadURI", {
uri: aURI.spec,
referrer: aReferrer ? aReferrer.spec : null,
loadOptions: {
uri: aURI.spec,
flags: Ci.nsIWebNavigation.LOAD_FLAGS_NONE,
referrer: aReferrer ? aReferrer.spec : null,
},
historyIndex: sessionHistory.requestedIndex,
});
return false;

View File

@ -133,14 +133,6 @@
if (!aURI)
aURI = "about:blank";
if (aCharset) {
try {
this.docShell.parentCharset = aCharset;
}
catch (e) {
}
}
if (!(aFlags & this.webNavigation.LOAD_FLAGS_FROM_EXTERNAL))
this.userTypedClear++;