Bug 1046022 - fix LoadURI to not let people load anything inside onbeforeunload, r=bz
This commit is contained in:
@@ -1322,8 +1322,12 @@ nsDocShell::LoadURI(nsIURI * aURI,
|
|||||||
NS_PRECONDITION((aLoadFlags & 0xf) == 0, "Should not have these flags set");
|
NS_PRECONDITION((aLoadFlags & 0xf) == 0, "Should not have these flags set");
|
||||||
|
|
||||||
// Note: we allow loads to get through here even if mFiredUnloadEvent is
|
// Note: we allow loads to get through here even if mFiredUnloadEvent is
|
||||||
// true; that case will get handled in LoadInternal or LoadHistoryEntry.
|
// true; that case will get handled in LoadInternal or LoadHistoryEntry,
|
||||||
if (IsPrintingOrPP()) {
|
// so we pass false as the second parameter to IsNavigationAllowed.
|
||||||
|
// However, we don't allow the page to change location *in the middle of*
|
||||||
|
// firing beforeunload, so we do need to check if *beforeunload* is currently
|
||||||
|
// firing, so we call IsNavigationAllowed rather than just IsPrintingOrPP.
|
||||||
|
if (!IsNavigationAllowed(true, false)) {
|
||||||
return NS_OK; // JS may not handle returning of an error code
|
return NS_OK; // JS may not handle returning of an error code
|
||||||
}
|
}
|
||||||
nsCOMPtr<nsIURI> referrer;
|
nsCOMPtr<nsIURI> referrer;
|
||||||
@@ -4279,9 +4283,11 @@ nsDocShell::IsPrintingOrPP(bool aDisplayErrorDialog)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
nsDocShell::IsNavigationAllowed(bool aDisplayPrintErrorDialog)
|
nsDocShell::IsNavigationAllowed(bool aDisplayPrintErrorDialog,
|
||||||
|
bool aCheckIfUnloadFired)
|
||||||
{
|
{
|
||||||
bool isAllowed = !IsPrintingOrPP(aDisplayPrintErrorDialog) && !mFiredUnloadEvent;
|
bool isAllowed = !IsPrintingOrPP(aDisplayPrintErrorDialog) &&
|
||||||
|
(!aCheckIfUnloadFired || !mFiredUnloadEvent);
|
||||||
if (!isAllowed) {
|
if (!isAllowed) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -521,8 +521,9 @@ protected:
|
|||||||
const char16_t *aDescription,
|
const char16_t *aDescription,
|
||||||
const char *aCSSClass,
|
const char *aCSSClass,
|
||||||
nsIChannel* aFailedChannel);
|
nsIChannel* aFailedChannel);
|
||||||
bool IsNavigationAllowed(bool aDisplayPrintErrorDialog = true);
|
|
||||||
bool IsPrintingOrPP(bool aDisplayErrorDialog = true);
|
bool IsPrintingOrPP(bool aDisplayErrorDialog = true);
|
||||||
|
bool IsNavigationAllowed(bool aDisplayPrintErrorDialog = true,
|
||||||
|
bool aCheckIfUnloadFired = true);
|
||||||
|
|
||||||
nsresult SetBaseUrlForWyciwyg(nsIContentViewer * aContentViewer);
|
nsresult SetBaseUrlForWyciwyg(nsIContentViewer * aContentViewer);
|
||||||
|
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ support-files =
|
|||||||
file_bug852909.png
|
file_bug852909.png
|
||||||
file_bug941562-child.html
|
file_bug941562-child.html
|
||||||
file_bug941562.html
|
file_bug941562.html
|
||||||
|
file_bug1046022.html
|
||||||
print_postdata.sjs
|
print_postdata.sjs
|
||||||
test-form_sjis.html
|
test-form_sjis.html
|
||||||
|
|
||||||
@@ -95,5 +96,7 @@ skip-if = e10s
|
|||||||
skip-if = e10s
|
skip-if = e10s
|
||||||
[browser_loadURI.js]
|
[browser_loadURI.js]
|
||||||
skip-if = e10s # Bug ?????? - event handler checks event.target is the content document and test e10s-utils doesn't do that.
|
skip-if = e10s # Bug ?????? - event handler checks event.target is the content document and test e10s-utils doesn't do that.
|
||||||
|
[browser_onbeforeunload_navigation.js]
|
||||||
|
skip-if = e10s
|
||||||
[browser_search_notification.js]
|
[browser_search_notification.js]
|
||||||
skip-if = e10s
|
skip-if = e10s
|
||||||
|
|||||||
179
docshell/test/browser/browser_onbeforeunload_navigation.js
Normal file
179
docshell/test/browser/browser_onbeforeunload_navigation.js
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
var contentWindow;
|
||||||
|
var originalLocation;
|
||||||
|
var currentTest = -1;
|
||||||
|
var stayingOnPage = true;
|
||||||
|
|
||||||
|
var TEST_PAGE = "http://mochi.test:8888/browser/docshell/test/browser/file_bug1046022.html";
|
||||||
|
var TARGETED_PAGE = "data:text/html," + encodeURIComponent("<body>Shouldn't be seeing this</body>");
|
||||||
|
|
||||||
|
var loadExpected = TEST_PAGE;
|
||||||
|
var testTab;
|
||||||
|
|
||||||
|
var loadStarted = false;
|
||||||
|
var tabStateListener = {
|
||||||
|
onStateChange: function(webprogress, request, stateFlags, status) {
|
||||||
|
let startDocumentFlags = Ci.nsIWebProgressListener.STATE_START |
|
||||||
|
Ci.nsIWebProgressListener.STATE_IS_DOCUMENT;
|
||||||
|
if ((stateFlags & startDocumentFlags) == startDocumentFlags) {
|
||||||
|
loadStarted = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onStatusChange: () => {},
|
||||||
|
onLocationChange: () => {},
|
||||||
|
onSecurityChange: () => {},
|
||||||
|
onProgressChange: () => {},
|
||||||
|
QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener])
|
||||||
|
};
|
||||||
|
|
||||||
|
function onTabLoaded(event) {
|
||||||
|
info("A document loaded in a tab!");
|
||||||
|
let loadedPage = event.target.location.href;
|
||||||
|
if (loadedPage == "about:blank" ||
|
||||||
|
event.originalTarget != testTab.linkedBrowser.contentDocument) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!loadExpected) {
|
||||||
|
ok(false, "Expected no page loads, but loaded " + loadedPage + " instead!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
is(loadedPage, loadExpected, "Loaded the expected page");
|
||||||
|
if (contentWindow) {
|
||||||
|
is(contentWindow.document, event.target, "Same doc");
|
||||||
|
}
|
||||||
|
if (onAfterPageLoad) {
|
||||||
|
onAfterPageLoad();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onAfterTargetedPageLoad() {
|
||||||
|
ok(!stayingOnPage, "We should only fire if we're expecting to let the onbeforeunload dialog proceed to the new location");
|
||||||
|
is(testTab.linkedBrowser.currentURI.spec, TARGETED_PAGE, "Should have loaded the expected new page");
|
||||||
|
|
||||||
|
runNextTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
function onTabModalDialogLoaded(node) {
|
||||||
|
let content = testTab.linkedBrowser.contentWindow;
|
||||||
|
ok(!loadStarted, "No load should be started.");
|
||||||
|
info(content.location.href);
|
||||||
|
is(content, contentWindow, "Window should be the same still.");
|
||||||
|
is(content.location.href, originalLocation, "Page should not have changed.");
|
||||||
|
is(content.mySuperSpecialMark, 42, "Page should not have refreshed.");
|
||||||
|
|
||||||
|
ok(!content.dialogWasInvoked, "Dialog should only be invoked once per test.");
|
||||||
|
content.dialogWasInvoked = true;
|
||||||
|
|
||||||
|
|
||||||
|
// Now listen for the dialog going away again...
|
||||||
|
let observer = new MutationObserver(function(muts) {
|
||||||
|
if (!node.parentNode) {
|
||||||
|
info("Dialog is gone");
|
||||||
|
observer.disconnect();
|
||||||
|
observer = null;
|
||||||
|
// If we're staying on the page, run the next test from here
|
||||||
|
if (stayingOnPage) {
|
||||||
|
// Evil, but necessary: without this delay, we manage to still break our
|
||||||
|
// own onbeforeunload code, because we'll basically cause a new load to be
|
||||||
|
// started while processing the destruction of the dialog for the old one.
|
||||||
|
executeSoon(runNextTest);
|
||||||
|
}
|
||||||
|
// if we accepted a page load in the dialog, the next test will get started
|
||||||
|
// by the load handler for that page loading
|
||||||
|
}
|
||||||
|
});
|
||||||
|
observer.observe(node.parentNode, {childList: true});
|
||||||
|
|
||||||
|
// If we're going to let the page load, set us up to listen for that happening:
|
||||||
|
if (!stayingOnPage) {
|
||||||
|
loadExpected = TARGETED_PAGE;
|
||||||
|
onAfterPageLoad = onAfterTargetedPageLoad;
|
||||||
|
}
|
||||||
|
|
||||||
|
let button = stayingOnPage ? node.ui.button1 : node.ui.button0;
|
||||||
|
// ... and then actually make the dialog go away
|
||||||
|
info("Clicking button: " + button.label);
|
||||||
|
EventUtils.synthesizeMouseAtCenter(button, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Listen for the dialog being created
|
||||||
|
Services.obs.addObserver(onTabModalDialogLoaded, "tabmodal-dialog-loaded", false);
|
||||||
|
|
||||||
|
var testFns = [
|
||||||
|
function(e) {
|
||||||
|
e.target.location.href = 'otherpage-href-set.html';
|
||||||
|
return "stop";
|
||||||
|
},
|
||||||
|
function(e) {
|
||||||
|
e.target.location.reload();
|
||||||
|
return "stop";
|
||||||
|
},
|
||||||
|
function(e) {
|
||||||
|
e.target.location.replace('otherpage-location-replaced.html');
|
||||||
|
return "stop";
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
function runNextTest() {
|
||||||
|
currentTest++;
|
||||||
|
if (currentTest >= testFns.length) {
|
||||||
|
if (!stayingOnPage) {
|
||||||
|
finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Run the same tests again, but this time let the navigation happen:
|
||||||
|
stayingOnPage = false;
|
||||||
|
currentTest = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (!stayingOnPage) {
|
||||||
|
onAfterPageLoad = runCurrentTest;
|
||||||
|
loadExpected = TEST_PAGE;
|
||||||
|
// Remove onbeforeunload handler, or this load will trigger the dialog...
|
||||||
|
contentWindow.onbeforeunload = null;
|
||||||
|
testTab.linkedBrowser.loadURI(TEST_PAGE);
|
||||||
|
} else {
|
||||||
|
runCurrentTest();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function runCurrentTest() {
|
||||||
|
// Reset things so we're sure the previous tests failings don't influence this one:
|
||||||
|
contentWindow = testTab.linkedBrowser.contentWindow;
|
||||||
|
contentWindow.mySuperSpecialMark = 42;
|
||||||
|
contentWindow.dialogWasInvoked = false;
|
||||||
|
originalLocation = contentWindow.location.href;
|
||||||
|
// And run this test:
|
||||||
|
info("Running test with onbeforeunload " + testFns[currentTest].toSource());
|
||||||
|
contentWindow.onbeforeunload = testFns[currentTest];
|
||||||
|
loadStarted = false;
|
||||||
|
contentWindow.location.href = TARGETED_PAGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
var onAfterPageLoad = runNextTest;
|
||||||
|
|
||||||
|
function test() {
|
||||||
|
waitForExplicitFinish();
|
||||||
|
gBrowser.addProgressListener(tabStateListener);
|
||||||
|
|
||||||
|
testTab = gBrowser.selectedTab = gBrowser.addTab();
|
||||||
|
testTab.linkedBrowser.addEventListener("load", onTabLoaded, true);
|
||||||
|
testTab.linkedBrowser.loadURI(TEST_PAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
registerCleanupFunction(function() {
|
||||||
|
// Remove the handler, or closing this tab will prove tricky:
|
||||||
|
if (contentWindow) {
|
||||||
|
try {
|
||||||
|
contentWindow.onbeforeunload = null;
|
||||||
|
} catch (ex) {}
|
||||||
|
}
|
||||||
|
contentWindow = null;
|
||||||
|
testTab.linkedBrowser.removeEventListener("load", onTabLoaded, true);
|
||||||
|
Services.obs.removeObserver(onTabModalDialogLoaded, "tabmodal-dialog-loaded");
|
||||||
|
gBrowser.removeProgressListener(tabStateListener);
|
||||||
|
gBrowser.removeTab(testTab);
|
||||||
|
});
|
||||||
|
|
||||||
10
docshell/test/browser/file_bug1046022.html
Normal file
10
docshell/test/browser/file_bug1046022.html
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Bug 1046022 - test navigating inside onbeforeunload</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
Waiting for onbeforeunload to hit...
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Reference in New Issue
Block a user