Bug 1651636 - reset the address bar when beforeunload prompts close, r=mak
authorGijs Kruitbosch <gijskruitbosch@gmail.com>
Wed, 15 Jul 2020 19:58:34 +0000
changeset 540624 8079eea73df334803da5b07322b19d32aa8ed9e3
parent 540623 8dee8cb525a2c7cff36a89be107eb50628619201
child 540625 f1fee6e8a267dd8b0cb80b359614c7704caa29f7
push id121828
push usergijskruitbosch@gmail.com
push dateWed, 15 Jul 2020 20:17:05 +0000
treeherderautoland@8079eea73df3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmak
bugs1651636
milestone80.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1651636 - reset the address bar when beforeunload prompts close, r=mak Differential Revision: https://phabricator.services.mozilla.com/D83213
browser/actors/PromptParent.jsm
browser/base/content/tabbrowser.js
browser/base/content/test/tabPrompts/browser.ini
browser/base/content/test/tabPrompts/browser_beforeunload_urlbar.js
browser/base/content/test/tabPrompts/file_beforeunload_stop.html
--- a/browser/actors/PromptParent.jsm
+++ b/browser/actors/PromptParent.jsm
@@ -164,17 +164,20 @@ class PromptParent extends JSWindowActor
       if (tabModalPrompt) {
         tabPrompt.removePrompt(tabModalPrompt);
       } else {
         needRemove = true;
       }
 
       this.unregisterPrompt(id);
 
-      PromptUtils.fireDialogEvent(window, "DOMModalDialogClosed", browser);
+      PromptUtils.fireDialogEvent(window, "DOMModalDialogClosed", browser, {
+        wasPermitUnload: args.inPermitUnload,
+        areLeaving: args.ok,
+      });
       resolver(args);
       browser.maybeLeaveModalState();
     };
 
     try {
       browser.enterModalState();
       let eventDetail = {
         tabPrompt: true,
--- a/browser/base/content/tabbrowser.js
+++ b/browser/base/content/tabbrowser.js
@@ -5413,16 +5413,36 @@
           }
 
           // If permissions/origins dictate so, bring tab to the front.
           this.selectedTab = tabForEvent;
         },
         true
       );
 
+      // When cancelling beforeunload tabmodal dialogs, reset the URL bar to
+      // avoid spoofing risks.
+      this.addEventListener(
+        "DOMModalDialogClosed",
+        event => {
+          if (
+            !event.detail?.wasPermitUnload ||
+            event.detail.areLeaving ||
+            event.target.nodeName != "browser"
+          ) {
+            return;
+          }
+          event.target.userTypedValue = null;
+          if (event.target == this.selectedBrowser) {
+            gURLBar.setURI();
+          }
+        },
+        true
+      );
+
       let onTabCrashed = event => {
         if (!event.isTrusted || !event.isTopFrame) {
           return;
         }
 
         let browser = event.originalTarget;
 
         // Preloaded browsers do not actually have any tabs. If one crashes,
--- a/browser/base/content/test/tabPrompts/browser.ini
+++ b/browser/base/content/test/tabPrompts/browser.ini
@@ -1,5 +1,7 @@
+[browser_beforeunload_urlbar.js]
+support-files = file_beforeunload_stop.html
 [browser_closeTabSpecificPanels.js]
 skip-if = (verify && debug && (os == 'linux')) || (fission && os == 'linux' && bits == 64 && os_version == '18.04') # Bug 1548664
 [browser_multiplePrompts.js]
 [browser_openPromptInBackgroundTab.js]
 support-files = openPromptOffTimeout.html
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/tabPrompts/browser_beforeunload_urlbar.js
@@ -0,0 +1,57 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const TEST_ROOT = getRootDirectory(gTestPath).replace(
+  "chrome://mochitests/content",
+  "http://example.com"
+);
+
+add_task(async function test_beforeunload_stay_clears_urlbar() {
+  await SpecialPowers.pushPrefEnv({
+    set: [["dom.require_user_interaction_for_beforeunload", false]],
+  });
+  const TEST_URL = TEST_ROOT + "file_beforeunload_stop.html";
+  await BrowserTestUtils.withNewTab(TEST_URL, async function(browser) {
+    gURLBar.focus();
+    const inputValue = "http://example.org/?q=typed";
+    gURLBar.inputField.value = inputValue.slice(0, -1);
+    EventUtils.sendString(inputValue.slice(-1));
+
+    let promptOpenedPromise = TestUtils.topicObserved("tabmodal-dialog-loaded");
+    EventUtils.synthesizeKey("VK_RETURN");
+    await promptOpenedPromise;
+    let promptElement = browser.parentNode.querySelector("tabmodalprompt");
+
+    // Click the cancel button
+    promptElement.querySelector(".tabmodalprompt-button1").click();
+
+    await TestUtils.waitForCondition(
+      () => promptElement.parentNode == null,
+      "tabprompt should be removed"
+    );
+    // Can't just compare directly with TEST_URL because the URL may be trimmed.
+    // Just need it to not be the example.org thing we typed in.
+    ok(
+      gURLBar.value.endsWith("_stop.html"),
+      "Url bar should be reset to point to the stop html file"
+    );
+    ok(
+      gURLBar.value.includes("example.com"),
+      "Url bar should be reset to example.com"
+    );
+    // Check the lock/identity icons are back:
+    is(
+      gURLBar.textbox.getAttribute("pageproxystate"),
+      "valid",
+      "Should be in valid pageproxy state."
+    );
+
+    // Now we need to get rid of the handler to avoid the prompt coming up when trying to close the
+    // tab when we exit `withNewTab`. :-)
+    await SpecialPowers.spawn(browser, [], function() {
+      content.window.onbeforeunload = null;
+    });
+  });
+});
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/tabPrompts/file_beforeunload_stop.html
@@ -0,0 +1,8 @@
+<body>
+  <p>I will ask not to be closed.</p>
+  <script>
+    window.onbeforeunload = function() {
+      return "true";
+    };
+  </script>
+</body>