Diff
Modified: trunk/LayoutTests/ChangeLog (214276 => 214277)
--- trunk/LayoutTests/ChangeLog 2017-03-22 20:46:31 UTC (rev 214276)
+++ trunk/LayoutTests/ChangeLog 2017-03-22 21:14:23 UTC (rev 214277)
@@ -1,3 +1,31 @@
+2017-03-22 Chris Dumez <cdu...@apple.com>
+
+ WebKit should disallow beforeunload alerts from web pages users have never interacted with
+ https://bugs.webkit.org/show_bug.cgi?id=169936
+ <rdar://problem/23798897>
+
+ Reviewed by Brent Fulgham.
+
+ * fast/events/before-unload-return-string-conversion-expected.txt:
+ * fast/events/before-unload-returnValue-expected.txt:
+ Rebaseline now that the CONFIRM MESSAGE is no longer shown. This is because there is
+ no user interaction with the page.
+
+ * fast/events/beforeunload-alert-no-user-interaction-expected.txt: Added.
+ * fast/events/beforeunload-alert-no-user-interaction.html: Added.
+ * fast/events/beforeunload-alert-user-interaction-expected.txt: Added.
+ * fast/events/beforeunload-alert-user-interaction.html: Added.
+ * fast/events/beforeunload-alert-user-interaction2-expected.txt: Added.
+ * fast/events/beforeunload-alert-user-interaction2.html: Added.
+ Add layout test coverage.
+
+ * fast/loader/form-submission-after-beforeunload-cancel.html:
+ * fast/loader/show-only-one-beforeunload-dialog.html:
+ * http/tests/misc/iframe-beforeunload-dialog-matching-ancestor-securityorigin.html:
+ * http/tests/misc/iframe-beforeunload-dialog-not-matching-ancestor-securityorigin.html:
+ Simulate user interaction with the page so that the CONFIRM MESSAGE log lines are still
+ shown.
+
2017-03-22 Nan Wang <n_w...@apple.com>
AX: WebKit is returning the wrong rangeForLine
Modified: trunk/LayoutTests/fast/events/before-unload-return-string-conversion-expected.txt (214276 => 214277)
--- trunk/LayoutTests/fast/events/before-unload-return-string-conversion-expected.txt 2017-03-22 20:46:31 UTC (rev 214276)
+++ trunk/LayoutTests/fast/events/before-unload-return-string-conversion-expected.txt 2017-03-22 21:14:23 UTC (rev 214277)
@@ -1,4 +1,3 @@
-CONFIRM NAVIGATION: PASS
Tests that the value returned from a beforeunload event handler gets converted to a string, even if the returnValue property was already set.
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
Modified: trunk/LayoutTests/fast/events/before-unload-returnValue-expected.txt (214276 => 214277)
--- trunk/LayoutTests/fast/events/before-unload-returnValue-expected.txt 2017-03-22 20:46:31 UTC (rev 214276)
+++ trunk/LayoutTests/fast/events/before-unload-returnValue-expected.txt 2017-03-22 21:14:23 UTC (rev 214277)
@@ -1,4 +1,3 @@
-CONFIRM NAVIGATION: This is beforeunload from the top level frame.
Tests the returnValue attribute of the BeforeUnloadEvent.
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
Added: trunk/LayoutTests/fast/events/beforeunload-alert-no-user-interaction-expected.txt (0 => 214277)
--- trunk/LayoutTests/fast/events/beforeunload-alert-no-user-interaction-expected.txt (rev 0)
+++ trunk/LayoutTests/fast/events/beforeunload-alert-no-user-interaction-expected.txt 2017-03-22 21:14:23 UTC (rev 214277)
@@ -0,0 +1,9 @@
+Tests that the beforeunload alert is not shown when the user did not interact with the page. You should NOT see a 'CONFIRM NAVIGATION' message at the top.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/fast/events/beforeunload-alert-no-user-interaction.html (0 => 214277)
--- trunk/LayoutTests/fast/events/beforeunload-alert-no-user-interaction.html (rev 0)
+++ trunk/LayoutTests/fast/events/beforeunload-alert-no-user-interaction.html 2017-03-22 21:14:23 UTC (rev 214277)
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script src=""
+<script>
+description("Tests that the beforeunload alert is not shown when the user did not interact with the page. You should NOT see a 'CONFIRM NAVIGATION' message at the top.");
+jsTestIsAsync = true;
+
+_onload_ = function() {
+ const testFrame = document.getElementById("testFrame");
+ testFrame.contentWindow._onbeforeunload_ = function(e) {
+ return "FAIL: a beforeunload alert was shown even though the user did not interact with the page.";
+ };
+ setTimeout(function() {
+ testFrame.src = ""
+ setTimeout(finishJSTest, 0);
+ }, 0);
+};
+</script>
+<iframe id="testFrame" src=""
+<script src=""
+</body>
+</html>
Added: trunk/LayoutTests/fast/events/beforeunload-alert-user-interaction-expected.txt (0 => 214277)
--- trunk/LayoutTests/fast/events/beforeunload-alert-user-interaction-expected.txt (rev 0)
+++ trunk/LayoutTests/fast/events/beforeunload-alert-user-interaction-expected.txt 2017-03-22 21:14:23 UTC (rev 214277)
@@ -0,0 +1,10 @@
+CONFIRM NAVIGATION: PASS: a beforeunload alert was shown.
+Tests that the beforeunload alert is shown when the user interacted with the page. You should see a 'CONFIRM NAVIGATION' message at the top.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/fast/events/beforeunload-alert-user-interaction.html (0 => 214277)
--- trunk/LayoutTests/fast/events/beforeunload-alert-user-interaction.html (rev 0)
+++ trunk/LayoutTests/fast/events/beforeunload-alert-user-interaction.html 2017-03-22 21:14:23 UTC (rev 214277)
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script src=""
+<script>
+description("Tests that the beforeunload alert is shown when the user interacted with the page. You should see a 'CONFIRM NAVIGATION' message at the top.");
+jsTestIsAsync = true;
+
+_onload_ = function() {
+ const testFrame = document.getElementById("testFrame");
+ testFrame.contentWindow._onbeforeunload_ = function(e) {
+ return "PASS: a beforeunload alert was shown.";
+ };
+ // Simulate a user interaction.
+ const testInput = document.getElementById("testInput");
+ testInput.focus();
+ if (window.eventSender)
+ eventSender.keyDown("a");
+ setTimeout(function() {
+ testFrame.src = ""
+ setTimeout(finishJSTest, 0);
+ }, 0);
+};
+</script>
+<iframe id="testFrame" src=""
+<input id="testInput" type="text"></input>
+<script src=""
+</body>
+</html>
Added: trunk/LayoutTests/fast/events/beforeunload-alert-user-interaction2-expected.txt (0 => 214277)
--- trunk/LayoutTests/fast/events/beforeunload-alert-user-interaction2-expected.txt (rev 0)
+++ trunk/LayoutTests/fast/events/beforeunload-alert-user-interaction2-expected.txt 2017-03-22 21:14:23 UTC (rev 214277)
@@ -0,0 +1,10 @@
+CONFIRM NAVIGATION: PASS: a beforeunload alert was shown.
+Tests that the beforeunload alert is shown when the user interacted with the page. You should see a 'CONFIRM NAVIGATION' message at the top.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/fast/events/beforeunload-alert-user-interaction2.html (0 => 214277)
--- trunk/LayoutTests/fast/events/beforeunload-alert-user-interaction2.html (rev 0)
+++ trunk/LayoutTests/fast/events/beforeunload-alert-user-interaction2.html 2017-03-22 21:14:23 UTC (rev 214277)
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script src=""
+<script src=""
+<script>
+description("Tests that the beforeunload alert is shown when the user interacted with the page. You should see a 'CONFIRM NAVIGATION' message at the top.");
+jsTestIsAsync = true;
+
+_onload_ = function() {
+ const testFrame = document.getElementById("testFrame");
+ testFrame.contentWindow._onbeforeunload_ = function(e) {
+ return "PASS: a beforeunload alert was shown.";
+ };
+ // Simulate a user interaction.
+ const testInput = document.getElementById("testInput");
+ UIHelper.activateAt(testInput.offsetLeft + 5, testInput.offsetTop + 5).then(function() {
+ setTimeout(function() {
+ testFrame.src = ""
+ setTimeout(finishJSTest, 0);
+ }, 0);
+ });
+};
+</script>
+<iframe id="testFrame" src=""
+<input id="testInput" type="text"></input>
+<script src=""
+</body>
+</html>
Modified: trunk/LayoutTests/fast/loader/form-submission-after-beforeunload-cancel.html (214276 => 214277)
--- trunk/LayoutTests/fast/loader/form-submission-after-beforeunload-cancel.html 2017-03-22 20:46:31 UTC (rev 214276)
+++ trunk/LayoutTests/fast/loader/form-submission-after-beforeunload-cancel.html 2017-03-22 21:14:23 UTC (rev 214277)
@@ -1,3 +1,4 @@
+<script src=""
<script>
if (window.testRunner) {
testRunner.waitUntilDone();
@@ -7,6 +8,11 @@
_confirmationDialogDisplayedOnce = false;
+function submitForm()
+{
+ document.forms[0].submit();
+}
+
window.addEventListener("beforeunload", function() {
if (window._confirmationDialogDisplayedOnce)
@@ -34,10 +40,12 @@
<p>This tests that submitting a form a second time after canceling the first submission in a onbeforeunload handler is allowed. To test manually, follow the instructions in the _javascript_ confirmation dialogs.</p>
<div id="console"></div>
-
+<input id="testButton" type="button" value="Click to submit form" _onclick_="submitForm()">
<form action="" method="POST">
</form>
<script>
-document.forms[0].submit();
-</script>
\ No newline at end of file
+// Simulate a user interaction with the page so that the beforeunload alert shows.
+const testButton = document.getElementById("testButton");
+UIHelper.activateAt(testButton.offsetLeft + 5, testButton.offsetTop + 5);
+</script>
Modified: trunk/LayoutTests/fast/loader/show-only-one-beforeunload-dialog.html (214276 => 214277)
--- trunk/LayoutTests/fast/loader/show-only-one-beforeunload-dialog.html 2017-03-22 20:46:31 UTC (rev 214276)
+++ trunk/LayoutTests/fast/loader/show-only-one-beforeunload-dialog.html 2017-03-22 21:14:23 UTC (rev 214277)
@@ -1,3 +1,4 @@
+<script src=""
<script>
if (window.testRunner) {
@@ -5,9 +6,16 @@
testRunner.waitUntilDone();
}
+function navigateFrame()
+{
+ window.location.href = '';
+}
+
window._onload_ = function()
{
- window.setTimeout("window.location.href = '';", 0);
+ // Simulate a user interaction with the page so that the beforeunload alert shows.
+ const testButton = document.getElementById("testButton");
+ UIHelper.activateAt(testButton.offsetLeft + 5, testButton.offsetTop + 5);
}
window._onbeforeunload_ = function()
@@ -20,6 +28,7 @@
This page has multiple iframes, each trying to bring up a beforeunload dialog.<br>
This page also has a beforeunload dialog, itself.<br>
Only the dialog from this top-level frame should display, and none of the iframe ones should display.<br>
+<input id="testButton" type="button" value="Click to navigate" _onclick_="navigateFrame()"><br>
<iframe src=""
<iframe src=""
</body>
Modified: trunk/LayoutTests/http/tests/misc/iframe-beforeunload-dialog-matching-ancestor-securityorigin.html (214276 => 214277)
--- trunk/LayoutTests/http/tests/misc/iframe-beforeunload-dialog-matching-ancestor-securityorigin.html 2017-03-22 20:46:31 UTC (rev 214276)
+++ trunk/LayoutTests/http/tests/misc/iframe-beforeunload-dialog-matching-ancestor-securityorigin.html 2017-03-22 21:14:23 UTC (rev 214277)
@@ -1,3 +1,4 @@
+<script src=""
<script>
if (window.testRunner) {
@@ -5,9 +6,16 @@
testRunner.waitUntilDone();
}
+function navigateFrame()
+{
+ window.location.href = '';
+}
+
window._onload_ = function()
{
- window.setTimeout("window.location.href = '';", 0);
+ // Simulate a user interaction with the page so that the beforeunload alert shows.
+ const testButton = document.getElementById("testButton");
+ UIHelper.activateAt(testButton.offsetLeft + 5, testButton.offsetTop + 5);
}
</script>
@@ -14,5 +22,6 @@
<body>
When viewed using the host 127.0.0.1, this page has an iframe whose security origin matches the main frame.<br>
The iframe has a beforeunload handler, and that handler should result in the display of the page dismissal dialog.<br>
+<input id="testButton" type="button" value="Click to navigate" _onclick_="navigateFrame()">
<iframe src=""
</body>
Modified: trunk/LayoutTests/http/tests/misc/iframe-beforeunload-dialog-not-matching-ancestor-securityorigin.html (214276 => 214277)
--- trunk/LayoutTests/http/tests/misc/iframe-beforeunload-dialog-not-matching-ancestor-securityorigin.html 2017-03-22 20:46:31 UTC (rev 214276)
+++ trunk/LayoutTests/http/tests/misc/iframe-beforeunload-dialog-not-matching-ancestor-securityorigin.html 2017-03-22 21:14:23 UTC (rev 214277)
@@ -1,3 +1,4 @@
+<script src=""
<script>
if (window.testRunner) {
@@ -5,9 +6,16 @@
testRunner.waitUntilDone();
}
+function navigateFrame()
+{
+ window.location.href = '';
+}
+
window._onload_ = function()
{
- window.setTimeout("window.location.href = '';", 0);
+ // Simulate a user interaction with the page so that the beforeunload alert shows.
+ const testButton = document.getElementById("testButton");
+ UIHelper.activateAt(testButton.offsetLeft + 5, testButton.offsetTop + 5);
}
</script>
@@ -14,5 +22,6 @@
<body>
When viewed using the host 127.0.0.1, this page has an iframe whose security origin is different from the main frame.<br>
The iframe has a beforeunload handler, and that handler should not result in the display of the page dismissal dialog since the security origins differ.<br>
+<input id="testButton" type="button" value="Click to navigate" _onclick_="navigateFrame()"><br>
<iframe src=""
</body>
Modified: trunk/LayoutTests/imported/w3c/ChangeLog (214276 => 214277)
--- trunk/LayoutTests/imported/w3c/ChangeLog 2017-03-22 20:46:31 UTC (rev 214276)
+++ trunk/LayoutTests/imported/w3c/ChangeLog 2017-03-22 21:14:23 UTC (rev 214277)
@@ -1,3 +1,16 @@
+2017-03-22 Chris Dumez <cdu...@apple.com>
+
+ WebKit should disallow beforeunload alerts from web pages users have never interacted with
+ https://bugs.webkit.org/show_bug.cgi?id=169936
+ <rdar://problem/23798897>
+
+ Reviewed by Brent Fulgham.
+
+ * web-platform-tests/html/browsers/browsing-the-web/unloading-documents/beforeunload-canceling-expected.txt:
+ * web-platform-tests/html/webappapis/scripting/events/compile-event-handler-settings-objects-expected.txt:
+ Rebaseline now that the CONFIRM MESSAGE lines are now longer shown. This is because there is no user interaction
+ with the page.
+
2017-03-22 Romain Bellessort <romain.belless...@crf.canon.fr>
[Readable Streams API] Implement ReadableStreamBYOBRequest respond() (readable stream state)
Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/html/browsers/browsing-the-web/unloading-documents/beforeunload-canceling-expected.txt (214276 => 214277)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/html/browsers/browsing-the-web/unloading-documents/beforeunload-canceling-expected.txt 2017-03-22 20:46:31 UTC (rev 214276)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/html/browsers/browsing-the-web/unloading-documents/beforeunload-canceling-expected.txt 2017-03-22 21:14:23 UTC (rev 214277)
@@ -1,13 +1,3 @@
-CONFIRM NAVIGATION:
-CONFIRM NAVIGATION: false
-CONFIRM NAVIGATION: true
-CONFIRM NAVIGATION: 0
-CONFIRM NAVIGATION: foo
-CONFIRM NAVIGATION: foo
-CONFIRM NAVIGATION: foo
-CONFIRM NAVIGATION: foo
-CONFIRM NAVIGATION: foo
-CONFIRM NAVIGATION: foo
PASS Returning a string must not cancel the event: CustomEvent, non-cancelable
PASS Returning a string must not cancel the event: CustomEvent, cancelable
Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/html/webappapis/scripting/events/compile-event-handler-settings-objects-expected.txt (214276 => 214277)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/html/webappapis/scripting/events/compile-event-handler-settings-objects-expected.txt 2017-03-22 20:46:31 UTC (rev 214276)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/html/webappapis/scripting/events/compile-event-handler-settings-objects-expected.txt 2017-03-22 21:14:23 UTC (rev 214277)
@@ -1,4 +1,3 @@
-CONFIRM NAVIGATION: undefined
PASS The Function instance must be created in the Realm of the node document
FAIL The entry settings object while executing the compiled callback via Web IDL's invoke must be that of the node document assert_equals: expected "/html/webappapis/scripting/events/resources/open-window.html" but got "/html/webappapis/scripting/events/open-window.html"
Modified: trunk/LayoutTests/platform/ios-simulator/TestExpectations (214276 => 214277)
--- trunk/LayoutTests/platform/ios-simulator/TestExpectations 2017-03-22 20:46:31 UTC (rev 214276)
+++ trunk/LayoutTests/platform/ios-simulator/TestExpectations 2017-03-22 21:14:23 UTC (rev 214277)
@@ -363,6 +363,7 @@
# This test relies on EventSender.keydown(), which is not supported on iOS
editing/caret/emoji.html [ Skip ]
webkit.org/b/155233 fast/events/max-tabindex-focus.html [ Skip ]
+fast/events/beforeunload-alert-user-interaction.html [ Skip ]
fast/forms/validation-bubble-escape-key-dismiss.html [ Skip ]
fast/forms/validation-message-maxLength.html [ Skip ]
fast/shadow-dom/shadow-host-removal-crash.html [ Skip ]
Modified: trunk/Source/WebCore/ChangeLog (214276 => 214277)
--- trunk/Source/WebCore/ChangeLog 2017-03-22 20:46:31 UTC (rev 214276)
+++ trunk/Source/WebCore/ChangeLog 2017-03-22 21:14:23 UTC (rev 214277)
@@ -1,3 +1,32 @@
+2017-03-22 Chris Dumez <cdu...@apple.com>
+
+ WebKit should disallow beforeunload alerts from web pages users have never interacted with
+ https://bugs.webkit.org/show_bug.cgi?id=169936
+ <rdar://problem/23798897>
+
+ Reviewed by Brent Fulgham.
+
+ WebKit should disallow beforeunload alerts from web pages users have never interacted with.
+ This reduces the risk of annoyance to the user and is allowed by the specification:
+ - https://html.spec.whatwg.org/multipage/browsers.html#prompt-to-unload-a-document (Step 8):
+ which says:
+ """
+ The user agent is encouraged to avoid asking the user for confirmation if it judges that doing
+ so would be annoying, deceptive, or pointless. A simple heuristic might be that if the user
+ has not interacted with the document, the user agent would not ask for confirmation before
+ unloading it.
+ """
+
+ Firefox already implements this, Chrome does not.
+
+ Tests: fast/events/beforeunload-alert-no-user-interaction.html
+ fast/events/beforeunload-alert-user-interaction.html
+ fast/events/beforeunload-alert-user-interaction2.html
+
+ * loader/FrameLoader.cpp:
+ (WebCore::shouldAskForNavigationConfirmation):
+ (WebCore::FrameLoader::dispatchBeforeUnloadEvent):
+
2017-03-22 Brent Fulgham <bfulg...@apple.com>
ASan violation in IconLoader::stopLoading
Modified: trunk/Source/WebCore/loader/FrameLoader.cpp (214276 => 214277)
--- trunk/Source/WebCore/loader/FrameLoader.cpp 2017-03-22 20:46:31 UTC (rev 214276)
+++ trunk/Source/WebCore/loader/FrameLoader.cpp 2017-03-22 21:14:23 UTC (rev 214277)
@@ -3068,14 +3068,15 @@
m_frame.document()->removeAllEventListeners();
}
-static bool shouldAskForNavigationConfirmation(const BeforeUnloadEvent& event)
+static bool shouldAskForNavigationConfirmation(Document& document, const BeforeUnloadEvent& event)
{
+ bool userDidInteractWithPage = document.topDocument().lastHandledUserGestureTimestamp() > 0;
// Web pages can request we ask for confirmation before navigating by:
// - Cancelling the BeforeUnloadEvent (modern way)
// - Setting the returnValue attribute on the BeforeUnloadEvent to a non-empty string.
// - Returning a non-empty string from the event handler, which is then set as returnValue
// attribute on the BeforeUnloadEvent.
- return event.defaultPrevented() || !event.returnValue().isEmpty();
+ return userDidInteractWithPage && (event.defaultPrevented() || !event.returnValue().isEmpty());
}
bool FrameLoader::dispatchBeforeUnloadEvent(Chrome& chrome, FrameLoader* frameLoaderBeingNavigated)
@@ -3102,7 +3103,7 @@
if (!beforeUnloadEvent->defaultPrevented())
document->defaultEventHandler(beforeUnloadEvent.get());
- if (!shouldAskForNavigationConfirmation(beforeUnloadEvent))
+ if (!shouldAskForNavigationConfirmation(*document, beforeUnloadEvent))
return true;
// If the navigating FrameLoader has already shown a beforeunload confirmation panel for the current navigation attempt,