tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

browser_targetTopLevelLinkClicksToBlank.js (8933B)


      1 /* Any copyright is dedicated to the Public Domain.
      2   http://creativecommons.org/publicdomain/zero/1.0/ */
      3 
      4 "use strict";
      5 
      6 /**
      7 * This test exercises the behaviour where user-initiated link clicks on
      8 * the top-level document result in pageloads in a _blank target in a new
      9 * browser window.
     10 */
     11 
     12 const TEST_PAGE = "https://example.com/browser/";
     13 const TEST_PAGE_2 = "https://example.com/browser/components/";
     14 const TEST_IFRAME_PAGE =
     15  getRootDirectory(gTestPath).replace(
     16    "chrome://mochitests/content",
     17    "https://example.com"
     18  ) + "dummy_iframe_page.html";
     19 
     20 // There is an <a> element with this href=".." in the TEST_PAGE
     21 // that we will click, which should take us up a level.
     22 const LINK_URL = "https://example.com/";
     23 
     24 /**
     25 * Test that a user-initiated link click results in targeting to a new
     26 * <browser> element, and that this properly sets the referrer on the newly
     27 * loaded document.
     28 */
     29 add_task(async function target_to_new_blank_browser() {
     30  let win = await BrowserTestUtils.openNewBrowserWindow();
     31  let originalTab = win.gBrowser.selectedTab;
     32  let originalBrowser = originalTab.linkedBrowser;
     33  BrowserTestUtils.startLoadingURIString(originalBrowser, TEST_PAGE);
     34  await BrowserTestUtils.browserLoaded(originalBrowser, false, TEST_PAGE);
     35 
     36  // Now set the targetTopLevelLinkClicksToBlank property to true, since it
     37  // defaults to false.
     38  originalBrowser.browsingContext.targetTopLevelLinkClicksToBlank = true;
     39 
     40  let newTabPromise = BrowserTestUtils.waitForNewTab(win.gBrowser, LINK_URL);
     41  await SpecialPowers.spawn(originalBrowser, [], async () => {
     42    let anchor = content.document.querySelector(`a[href=".."]`);
     43    let userInput = content.windowUtils.setHandlingUserInput(true);
     44    try {
     45      anchor.click();
     46    } finally {
     47      userInput.destruct();
     48    }
     49  });
     50  let newTab = await newTabPromise;
     51  let newBrowser = newTab.linkedBrowser;
     52 
     53  Assert.notStrictEqual(
     54    originalBrowser,
     55    newBrowser,
     56    "A new browser should have been created."
     57  );
     58  await SpecialPowers.spawn(newBrowser, [TEST_PAGE], async referrer => {
     59    Assert.equal(
     60      content.document.referrer,
     61      referrer,
     62      "Should have gotten the right referrer set"
     63    );
     64  });
     65  await BrowserTestUtils.switchTab(win.gBrowser, originalTab);
     66  BrowserTestUtils.removeTab(newTab);
     67 
     68  // Now do the same thing with a subframe targeting "_top". This should also
     69  // get redirected to "_blank".
     70  BrowserTestUtils.startLoadingURIString(originalBrowser, TEST_IFRAME_PAGE);
     71  await BrowserTestUtils.browserLoaded(
     72    originalBrowser,
     73    false,
     74    TEST_IFRAME_PAGE
     75  );
     76 
     77  newTabPromise = BrowserTestUtils.waitForNewTab(win.gBrowser, LINK_URL);
     78  let frameBC1 = originalBrowser.browsingContext.children[0];
     79  Assert.ok(frameBC1, "Should have found a subframe BrowsingContext");
     80 
     81  await SpecialPowers.spawn(frameBC1, [LINK_URL], async linkUrl => {
     82    let anchor = content.document.createElement("a");
     83    anchor.setAttribute("href", linkUrl);
     84    anchor.setAttribute("target", "_top");
     85    content.document.body.appendChild(anchor);
     86    let userInput = content.windowUtils.setHandlingUserInput(true);
     87    try {
     88      anchor.click();
     89    } finally {
     90      userInput.destruct();
     91    }
     92  });
     93  newTab = await newTabPromise;
     94  newBrowser = newTab.linkedBrowser;
     95 
     96  Assert.notStrictEqual(
     97    originalBrowser,
     98    newBrowser,
     99    "A new browser should have been created."
    100  );
    101  await SpecialPowers.spawn(
    102    newBrowser,
    103    [frameBC1.currentURI.spec],
    104    async referrer => {
    105      Assert.equal(
    106        content.document.referrer,
    107        referrer,
    108        "Should have gotten the right referrer set"
    109      );
    110    }
    111  );
    112  await BrowserTestUtils.switchTab(win.gBrowser, originalTab);
    113  BrowserTestUtils.removeTab(newTab);
    114 
    115  await BrowserTestUtils.closeWindow(win);
    116 });
    117 
    118 /**
    119 * Test that we don't target to _blank loads caused by:
    120 * 1. POST requests
    121 * 2. Any load that isn't "normal" (in the nsIDocShell.LOAD_CMD_NORMAL sense)
    122 * 3. Any loads that are caused by location.replace
    123 * 4. Any loads that were caused by setting location.href
    124 * 5. Link clicks fired without user interaction.
    125 */
    126 add_task(async function skip_blank_target_for_some_loads() {
    127  let win = await BrowserTestUtils.openNewBrowserWindow();
    128  let currentBrowser = win.gBrowser.selectedBrowser;
    129  BrowserTestUtils.startLoadingURIString(currentBrowser, TEST_PAGE);
    130  await BrowserTestUtils.browserLoaded(currentBrowser, false, TEST_PAGE);
    131 
    132  // Now set the targetTopLevelLinkClicksToBlank property to true, since it
    133  // defaults to false.
    134  currentBrowser.browsingContext.targetTopLevelLinkClicksToBlank = true;
    135 
    136  let ensureSingleBrowser = () => {
    137    Assert.equal(
    138      win.gBrowser.browsers.length,
    139      1,
    140      "There should only be 1 browser."
    141    );
    142 
    143    Assert.ok(
    144      currentBrowser.browsingContext.targetTopLevelLinkClicksToBlank,
    145      "Should still be targeting top-level clicks to _blank"
    146    );
    147  };
    148 
    149  // First we'll test a POST request
    150  let sameBrowserLoad = BrowserTestUtils.browserLoaded(
    151    currentBrowser,
    152    false,
    153    TEST_PAGE
    154  );
    155  await SpecialPowers.spawn(currentBrowser, [], async () => {
    156    let doc = content.document;
    157    let form = doc.createElement("form");
    158    form.setAttribute("method", "post");
    159    doc.body.appendChild(form);
    160    let userInput = content.windowUtils.setHandlingUserInput(true);
    161    try {
    162      form.submit();
    163    } finally {
    164      userInput.destruct();
    165    }
    166  });
    167  await sameBrowserLoad;
    168  ensureSingleBrowser();
    169 
    170  // Next, we'll try a non-normal load - specifically, we'll try a reload.
    171  // Since we've got a page loaded via a POST request, an attempt to reload
    172  // will cause the "repost" dialog to appear, so we temporarily allow the
    173  // repost to go through with the always_accept testing pref.
    174  await SpecialPowers.pushPrefEnv({
    175    set: [["dom.confirm_repost.testing.always_accept", true]],
    176  });
    177  sameBrowserLoad = BrowserTestUtils.browserLoaded(
    178    currentBrowser,
    179    false,
    180    TEST_PAGE
    181  );
    182  await SpecialPowers.spawn(currentBrowser, [], async () => {
    183    let userInput = content.windowUtils.setHandlingUserInput(true);
    184    try {
    185      content.location.reload();
    186    } finally {
    187      userInput.destruct();
    188    }
    189  });
    190  await sameBrowserLoad;
    191  ensureSingleBrowser();
    192  await SpecialPowers.popPrefEnv();
    193 
    194  // Next, we'll try a location.replace
    195  sameBrowserLoad = BrowserTestUtils.browserLoaded(
    196    currentBrowser,
    197    false,
    198    TEST_PAGE_2
    199  );
    200  await SpecialPowers.spawn(currentBrowser, [TEST_PAGE_2], async page2 => {
    201    let userInput = content.windowUtils.setHandlingUserInput(true);
    202    try {
    203      content.location.replace(page2);
    204    } finally {
    205      userInput.destruct();
    206    }
    207  });
    208  await sameBrowserLoad;
    209  ensureSingleBrowser();
    210 
    211  // Finally we'll try setting location.href
    212  sameBrowserLoad = BrowserTestUtils.browserLoaded(
    213    currentBrowser,
    214    false,
    215    TEST_PAGE
    216  );
    217  await SpecialPowers.spawn(currentBrowser, [TEST_PAGE], async page1 => {
    218    let userInput = content.windowUtils.setHandlingUserInput(true);
    219    try {
    220      content.location.href = page1;
    221    } finally {
    222      userInput.destruct();
    223    }
    224  });
    225  await sameBrowserLoad;
    226  ensureSingleBrowser();
    227 
    228  // Now that we're back at TEST_PAGE, let's try a scripted link click. This
    229  // shouldn't target to _blank.
    230  sameBrowserLoad = BrowserTestUtils.browserLoaded(
    231    currentBrowser,
    232    false,
    233    LINK_URL
    234  );
    235  await SpecialPowers.spawn(currentBrowser, [], async () => {
    236    let anchor = content.document.querySelector(`a[href=".."]`);
    237    anchor.click();
    238  });
    239  await sameBrowserLoad;
    240  ensureSingleBrowser();
    241 
    242  // A javascript:void(0); link should also not target to _blank.
    243  sameBrowserLoad = BrowserTestUtils.browserLoaded(
    244    currentBrowser,
    245    false,
    246    TEST_PAGE
    247  );
    248  await SpecialPowers.spawn(currentBrowser, [TEST_PAGE], async newPageURL => {
    249    let anchor = content.document.querySelector(`a[href=".."]`);
    250    anchor.href = "javascript:void(0);";
    251    anchor.addEventListener("click", () => {
    252      content.location.href = newPageURL;
    253    });
    254    let userInput = content.windowUtils.setHandlingUserInput(true);
    255    try {
    256      anchor.click();
    257    } finally {
    258      userInput.destruct();
    259    }
    260  });
    261  await sameBrowserLoad;
    262  ensureSingleBrowser();
    263 
    264  // Let's also try a non-void javascript: location.
    265  sameBrowserLoad = BrowserTestUtils.browserLoaded(
    266    currentBrowser,
    267    false,
    268    TEST_PAGE
    269  );
    270  await SpecialPowers.spawn(currentBrowser, [TEST_PAGE], async newPageURL => {
    271    let anchor = content.document.querySelector(`a[href=".."]`);
    272    anchor.href = `javascript:"string-to-navigate-to"`;
    273    anchor.addEventListener("click", () => {
    274      content.location.href = newPageURL;
    275    });
    276    let userInput = content.windowUtils.setHandlingUserInput(true);
    277    try {
    278      anchor.click();
    279    } finally {
    280      userInput.destruct();
    281    }
    282  });
    283  await sameBrowserLoad;
    284  ensureSingleBrowser();
    285 
    286  await BrowserTestUtils.closeWindow(win);
    287 });