tor-browser

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

browser_net_html-preview.js (6629B)


      1 /* Any copyright is dedicated to the Public Domain.
      2   http://creativecommons.org/publicdomain/zero/1.0/ */
      3 
      4 "use strict";
      5 
      6 /**
      7 * Tests if different response content types are handled correctly.
      8 */
      9 
     10 const httpServer = createTestHTTPServer();
     11 httpServer.registerContentType("html", "text/html");
     12 
     13 const BASE_URL = `http://localhost:${httpServer.identity.primaryPort}/`;
     14 
     15 const REDIRECT_URL = BASE_URL + "redirect.html";
     16 
     17 // In all content previewed as HTML we ensure using proper html, head and body in order to
     18 // prevent having them added by the <browser> when loaded as a preview.
     19 function addBaseHtmlElements(body) {
     20  return `<html><head></head><body>${body}</body></html>`;
     21 }
     22 
     23 const TEST_PAGES = {
     24  // This page asserts we can redirect to another URL, even if JS happen to be executed
     25  redirect: addBaseHtmlElements(
     26    `Fetch 1<script>window.parent.location.href = "${REDIRECT_URL}";</script>`
     27  ),
     28 
     29  // #1 This page asserts that JS is disabled
     30  js: addBaseHtmlElements(
     31    `Fetch 2<script>document.write("JS activated")</script>`
     32  ),
     33 
     34  // #2 This page asserts that links and forms are disabled
     35  forms: addBaseHtmlElements(
     36    `Fetch 3<a href="${REDIRECT_URL}">link</a> -- <form action="${REDIRECT_URL}"><input type="submit"></form>`
     37  ),
     38 
     39  // #3 This page asserts responses with line breaks work
     40  lineBreak: addBaseHtmlElements(`
     41  <a href="#" id="link1">link1</a>
     42  <a href="#" id="link2">link2</a>
     43  `),
     44 
     45  // #4 This page asserts that we apply inline styles
     46  styles: addBaseHtmlElements(`<p style="color: red;">Hello World</p>`),
     47 
     48  // #5 This page asserts that (multiple) Content-Security-Policy headers are applied
     49  csp: addBaseHtmlElements(`
     50  <base href="https://example.com/">
     51 
     52  <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2P4v5ThPwAG7wKklwQ/bwAAAABJRU5ErkJggg==">
     53  <iframe src="/foo.html"></iframe>
     54  `),
     55 };
     56 
     57 // Use fetch in order to prevent actually running this code in the test page
     58 const TEST_HTML = addBaseHtmlElements(
     59  `<div id="to-copy">HTML</div><script>` +
     60    Object.keys(TEST_PAGES)
     61      .map(name => `fetch("${BASE_URL}fetch-${name}.html");`)
     62      .join("\n") +
     63    `</script>`
     64 );
     65 const TEST_URL = BASE_URL + "doc-html-preview.html";
     66 
     67 httpServer.registerPathHandler(
     68  "/doc-html-preview.html",
     69  (request, response) => {
     70    response.setStatusLine(request.httpVersion, 200, "OK");
     71    response.write(TEST_HTML);
     72  }
     73 );
     74 
     75 for (const [name, content] of Object.entries(TEST_PAGES)) {
     76  httpServer.registerPathHandler(`/fetch-${name}.html`, (request, response) => {
     77    response.setStatusLine(request.httpVersion, 200, "OK");
     78 
     79    if (name === "csp") {
     80      // Duplicate un-merged headers
     81      response.setHeaderNoCheck("Content-Security-Policy", "img-src 'none'");
     82      response.setHeaderNoCheck("Content-Security-Policy", "base-uri 'self'");
     83    }
     84 
     85    response.write(content);
     86  });
     87 }
     88 
     89 httpServer.registerPathHandler("/redirect.html", (request, response) => {
     90  response.setStatusLine(request.httpVersion, 200, "OK");
     91  response.write("Redirected!");
     92 });
     93 
     94 add_task(async function () {
     95  // Enable async events so that clicks on preview iframe's links are correctly
     96  // going through the parent process which is meant to cancel any mousedown.
     97  await pushPref("test.events.async.enabled", true);
     98 
     99  const { monitor } = await initNetMonitor(TEST_URL, { requestCount: 3 });
    100  info("Starting test... ");
    101 
    102  const { document, store, windowRequire } = monitor.panelWin;
    103  const Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
    104 
    105  store.dispatch(Actions.batchEnable(false));
    106 
    107  const onNetworkEvent = waitForNetworkEvents(
    108    monitor,
    109    1 + Object.keys(TEST_PAGES).length
    110  );
    111  await reloadBrowser();
    112  await onNetworkEvent;
    113 
    114  // The new lines are stripped when using outerHTML to retrieve HTML content of the preview iframe
    115  await selectIndexAndWaitForHtmlView(0, "initial-page", TEST_HTML);
    116  let index = 1;
    117  for (const [name, content] of Object.entries(TEST_PAGES)) {
    118    await selectIndexAndWaitForHtmlView(index, name, content);
    119    index++;
    120  }
    121 
    122  await teardown(monitor);
    123 
    124  async function selectIndexAndWaitForHtmlView(
    125    index_,
    126    name,
    127    expectedHtmlPreview
    128  ) {
    129    info(`Select the request "${name}" #${index_}`);
    130    const onResponseContent = monitor.panelWin.api.once(
    131      TEST_EVENTS.RECEIVED_RESPONSE_CONTENT
    132    );
    133    store.dispatch(Actions.selectRequestByIndex(index_));
    134 
    135    document.querySelector("#response-tab").click();
    136 
    137    const [browser] = await waitForDOM(
    138      document,
    139      "#response-panel .html-preview browser"
    140    );
    141 
    142    await BrowserTestUtils.browserLoaded(browser);
    143 
    144    info("Wait for response content to be loaded");
    145    await onResponseContent;
    146 
    147    is(
    148      browser.browsingContext.currentWindowGlobal.isInProcess,
    149      false,
    150      "The preview is loaded in a content process"
    151    );
    152 
    153    await SpecialPowers.spawn(
    154      browser.browsingContext,
    155      [expectedHtmlPreview],
    156      async function (expectedHtml) {
    157        is(
    158          content.document.documentElement.outerHTML,
    159          expectedHtml,
    160          "The text shown in the browser is incorrect for the html request."
    161        );
    162      }
    163    );
    164 
    165    if (name === "style") {
    166      await SpecialPowers.spawn(browser.browsingContext, [], async function () {
    167        const p = content.document.querySelector("p");
    168        const computed = content.window.getComputedStyle(p);
    169        is(
    170          computed.getPropertyValue("color"),
    171          "rgb(255, 0, 0)",
    172          "The inline style was not applied"
    173        );
    174      });
    175    }
    176 
    177    if (name == "csp") {
    178      await SpecialPowers.spawn(browser.browsingContext, [], async function () {
    179        is(
    180          content.document.querySelector("img").complete,
    181          false,
    182          "img was blocked"
    183        );
    184        is(
    185          content.document.querySelector("iframe").src,
    186          "/foo.html",
    187          "URL of iframe was not changed by <base>"
    188        );
    189      });
    190    }
    191 
    192    // Only assert copy to clipboard on the first test page
    193    if (name == "initial-page") {
    194      await waitForClipboardPromise(async function () {
    195        await SpecialPowers.spawn(
    196          browser.browsingContext,
    197          [],
    198          async function () {
    199            const elt = content.document.getElementById("to-copy");
    200            EventUtils.synthesizeMouseAtCenter(elt, { clickCount: 2 }, content);
    201            await new Promise(r =>
    202              elt.addEventListener("dblclick", r, { once: true })
    203            );
    204            EventUtils.synthesizeKey("c", { accelKey: true }, content);
    205          }
    206        );
    207      }, "HTML");
    208    }
    209  }
    210 });