Commit 2447cd6e authored by Maurice Dauer's avatar Maurice Dauer Committed by Pier Angelo Vendrame
Browse files

Bug 2025170 - Pass correct report index for blocked popups, r=emz

parent 28fb221a
Loading
Loading
Loading
Loading
+186 −3
Original line number Diff line number Diff line
@@ -85,7 +85,190 @@ add_task(async function test_opening_blocked_popups_privateWindow() {
  await BrowserTestUtils.closeWindow(win);
});

async function testPopupBlockingToolbar(tab) {
// This is a test for Bug 1988311.
// Make sure that everything also functions correctly on special pages,
// such as "about:privatebrowsing".
add_task(async function test_opening_blocked_popups_about_privatebrowsing() {
  const tab = await BrowserTestUtils.openNewForegroundTab(
    gBrowser,
    "about:privatebrowsing"
  );

  const browser = tab.linkedBrowser;
  const uri = Services.io.newURI(
    "javascript:" +
      `window.open("${baseURL}" + "popup_blocker_a.html");` +
      `window.open("${baseURL}" + "popup_blocker_b.html");`
  );
  const triggeringPrincipal =
    Services.scriptSecurityManager.getSystemPrincipal();

  browser.loadURI(uri, { triggeringPrincipal });
  await testPopupBlockingToolbar(tab);
});

// Bug 2006600.
// When a notification has been dismissed by a user, it should not appear
// again when switching to a different tab and back.
add_task(async function test_dismissed_notification_switch_tabs() {
  // Open the test page.
  const tab = await BrowserTestUtils.openNewForegroundTab(
    gBrowser,
    baseURL + "popup_blocker.html"
  );

  // Wait for the notification.
  let notification;
  await TestUtils.waitForCondition(
    () =>
      (notification = gBrowser
        .getNotificationBox()
        .getNotificationWithValue("popup-blocked"))
  );

  // Click dismiss button.
  const mozButton = notification.shadowRoot.querySelector("moz-button.close");
  mozButton.click();

  // Open a new (foreground) tab and switch back.
  const differentTab = await BrowserTestUtils.openNewForegroundTab(
    gBrowser,
    "about:blank"
  );
  await BrowserTestUtils.switchTab(gBrowser, tab);

  // Make sure no notification appears.
  try {
    await TestUtils.waitForCondition(
      () =>
        (notification = gBrowser
          .getNotificationBox()
          .getNotificationWithValue("popup-blocked")),
      null,
      50,
      10
    );
  } catch (e) {
    notification = null;
  }
  ok(!notification, "Notification should not reappear");

  gBrowser.removeTab(tab);
  gBrowser.removeTab(differentTab);
});

// Bug 2025170.
// "Allow" should unblock all popups across multiple browsing contexts
// without erroring on out-of-bounds per-document indices.
add_task(async function test_bug2025170_allow_all() {
  const tab = await BrowserTestUtils.openNewForegroundTab(
    gBrowser,
    "https://example.com"
  );

  await SpecialPowers.spawn(
    tab.linkedBrowser,
    [baseURL + "popup_blocker.html"],
    uri => {
      for (let i = 0; i < 2; i++) {
        let iframe = content.document.createElement("iframe");
        iframe.src = uri;
        content.document.body.appendChild(iframe);
      }
    }
  );

  // Because popup_blocker.html is calling window.open() with target
  // window names, we expect only two new tabs.
  await testPopupBlockingToolbar(
    tab,
    /*expectedBlocked=*/ 4,
    /*expectedOpened=*/ 2
  );
});

// Bug 2025170.
// Make sure the correct popup is opened when the blocked popup list
// spans multiple browsing contexts.
add_task(async function test_bug2025170_unblock_popup() {
  const tab = await BrowserTestUtils.openNewForegroundTab(
    gBrowser,
    "https://example.com"
  );

  await SpecialPowers.spawn(
    tab.linkedBrowser,
    [baseURL + "popup_blocker.html"],
    uri => {
      for (let i = 0; i < 2; i++) {
        let iframe = content.document.createElement("iframe");
        iframe.src = uri;
        content.document.body.appendChild(iframe);
      }
    }
  );

  // Wait for the popup-blocked notification.
  let notification;
  await TestUtils.waitForCondition(
    () =>
      (notification = gBrowser
        .getNotificationBox()
        .getNotificationWithValue("popup-blocked"))
  );

  // Show the menu.
  const popupShown = BrowserTestUtils.waitForEvent(window, "popupshown");
  const popupFilled = waitForBlockedPopups(4, { doc: document });
  EventUtils.synthesizeMouseAtCenter(
    notification.buttonContainer.querySelector("button"),
    {},
    window
  );

  // Wait for the menu.
  const popupEvent = await popupShown;
  const menu = popupEvent.target;
  is(menu.id, "blockedPopupOptions", "Blocked popup menu shown");

  await popupFilled;

  const popupItems = menu.querySelectorAll("[popupReportIndex]");
  is(popupItems.length, 4, "Should have 4 blocked popup items");

  // Track new tabs.
  const popupTabs = [];
  const onTabOpen = e => popupTabs.push(e.target);
  gBrowser.tabContainer.addEventListener("TabOpen", onTabOpen);

  // The last item in the flattened list appears first in DOM order.
  // Without the fix, its popupReportIndex would be out of bounds.
  popupItems[0].doCommand();

  await TestUtils.waitForCondition(
    () =>
      popupTabs.length == 1 &&
      popupTabs[0].linkedBrowser.currentURI.spec != "about:blank",
    "Waiting for popup tab to open"
  );
  ok(
    popupTabs[0].linkedBrowser.currentURI.spec.endsWith("popup_blocker_b.html"),
    "Should have opened popup_blocker_b.html"
  );

  gBrowser.tabContainer.removeEventListener("TabOpen", onTabOpen);

  // Clean up.
  menu.hidePopup();
  BrowserTestUtils.removeTab(popupTabs[0]);
  BrowserTestUtils.removeTab(tab);
});

async function testPopupBlockingToolbar(
  tab,
  expectedBlocked = 2,
  expectedOpened = 2
) {
  let win = tab.ownerGlobal;
  // Wait for the popup-blocked notification.
  let notification;
@@ -98,7 +281,7 @@ async function testPopupBlockingToolbar(tab) {

  // Show the menu.
  let popupShown = BrowserTestUtils.waitForEvent(win, "popupshown");
  let popupFilled = waitForBlockedPopups(2, {
  let popupFilled = waitForBlockedPopups(expectedBlocked, {
    doc: win.document,
  });
  EventUtils.synthesizeMouseAtCenter(
@@ -124,7 +307,7 @@ async function testPopupBlockingToolbar(tab) {
  allow.doCommand();
  await TestUtils.waitForCondition(
    () =>
      popupTabs.length == 2 &&
      popupTabs.length == expectedOpened &&
      popupTabs.every(
        aTab => aTab.linkedBrowser.currentURI.spec != "about:blank"
      )
+6 −4
Original line number Diff line number Diff line
@@ -241,9 +241,11 @@ export var PopupAndRedirectBlockerObserver = {
      document.l10n.setAttributes(menuitem, "popup-show-popup-menuitem", {
        popupURI: blockedPopup.popupWindowURISpec,
      });
      menuitem.setAttribute("popupReportIndex", i);
      // The report index is the index into the blocked popup list
      // maintained by the window where this popup was blocked.
      menuitem.setAttribute("popupReportIndex", blockedPopup.reportIndex);
      // Store the source inner window id, so we can check if the document
      // that triggered the redirect is still the same.
      // that triggered the popup is still the same.
      menuitem.setAttribute("popupInnerWindowId", blockedPopup.innerWindowId);
      // Store the browser for the current tab. The active tab may change,
      // so we keep a reference to it.
@@ -321,12 +323,12 @@ export var PopupAndRedirectBlockerObserver = {
  showBlockedPopup(aEvent) {
    const { browser, browsingContext } = aEvent.target;
    const innerWindowId = aEvent.target.getAttribute("popupInnerWindowId");
    const popupReportIndex = aEvent.target.getAttribute("popupReportIndex");
    const reportIndex = aEvent.target.getAttribute("popupReportIndex");

    browser.popupAndRedirectBlocker.unblockPopup(
      browsingContext,
      innerWindowId,
      popupReportIndex
      reportIndex
    );
  },

+5 −4
Original line number Diff line number Diff line
@@ -91,11 +91,12 @@ export class PopupAndRedirectBlockingChild extends JSWindowActorChild {
    );
    const result = [];

    for (let i = 0; i < length; ++i) {
      const popup = state.popups[i];
    for (let reportIndex = 0; reportIndex < length; ++reportIndex) {
      const popup = state.popups[reportIndex];
      const { popupWindowURISpec } = popup;
      result.push({
        popupWindowURISpec,
        reportIndex,
      });
    }

@@ -114,8 +115,8 @@ export class PopupAndRedirectBlockingChild extends JSWindowActorChild {
  }

  #unblockPopup(aMessage) {
    const idx = aMessage.data.index;
    const popup = this.#getOrCreateDocState().popups[idx];
    const reportIndex = aMessage.data.reportIndex;
    const popup = this.#getOrCreateDocState().popups[reportIndex];

    if (popup?.requestingWindow?.document == popup.requestingDocument) {
      popup.requestingWindow.open(
+10 −5
Original line number Diff line number Diff line
@@ -84,6 +84,7 @@ export class PopupAndRedirectBlocker {
            browsingContext: currentBC,
            innerWindowId: currentWG.innerWindowId,
            popupWindowURISpec: popup.popupWindowURISpec,
            reportIndex: popup.reportIndex,
          });
        }
      }
@@ -121,14 +122,14 @@ export class PopupAndRedirectBlocker {
    };
  }

  unblockPopup(aBrowsingContext, aInnerWindowId, aPopupIndex) {
  unblockPopup(aBrowsingContext, aInnerWindowId, aReportIndex) {
    const sourceWG = aBrowsingContext.currentWindowGlobal;
    if (sourceWG?.innerWindowId != aInnerWindowId) {
      return;
    }

    const actor = sourceWG.getActor("PopupAndRedirectBlocking");
    actor.sendAsyncMessage("UnblockPopup", { index: aPopupIndex });
    actor.sendAsyncMessage("UnblockPopup", { reportIndex: aReportIndex });
  }

  unblockRedirect(aBrowsingContext, aInnerWindowId, aRedirectURISpec) {
@@ -145,9 +146,13 @@ export class PopupAndRedirectBlocker {

  async unblockAllPopups() {
    const popups = await this.getBlockedPopups();
    for (let idx = 0; idx < popups.length; ++idx) {
      const popup = popups[idx];
      this.unblockPopup(popup.browsingContext, popup.innerWindowId, idx);
    for (let i = 0; i < popups.length; ++i) {
      const popup = popups[i];
      this.unblockPopup(
        popup.browsingContext,
        popup.innerWindowId,
        popup.reportIndex
      );
    }
  }