tor-browser

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

browser_SpecialPowersForProcessSpawn.js (5411B)


      1 "use strict";
      2 
      3 // Tests SpecialPowersForProcess spawn() in browser chrome mochitests.
      4 // An xpcshell version of this test exists at
      5 // testing/mochitest/tests/Harness_sanity/test_SpecialPowersForProcessSpawn.js
      6 
      7 const { SpecialPowersForProcess } = ChromeUtils.importESModule(
      8  "resource://testing-common/SpecialPowersProcessActor.sys.mjs"
      9 );
     10 
     11 const scope = this;
     12 const interceptedMessages = [];
     13 add_setup(() => {
     14  const orig_record = SimpleTest.record;
     15  SimpleTest.record = (condition, name, diag, stack, expected) => {
     16    if (name?.startsWith?.("CHECK_THIS:")) {
     17      interceptedMessages.push(name);
     18    }
     19    return orig_record(condition, name, diag, stack, expected);
     20  };
     21  const orig_info = SimpleTest.info;
     22  SimpleTest.info = msg => {
     23    if (msg?.startsWith?.("CHECK_THIS:")) {
     24      interceptedMessages.push(msg);
     25    }
     26    return orig_info(msg);
     27  };
     28  registerCleanupFunction(() => {
     29    SimpleTest.record = orig_record;
     30    SimpleTest.info = orig_info;
     31  });
     32 });
     33 
     34 // Tests that SpecialPowersForProcess can spawn() in processes that the test
     35 // grabbed off a contentPage, even after the original page navigated/closed.
     36 add_task(async function test_SpecialPowersForProcess_spawn() {
     37  interceptedMessages.length = 0;
     38 
     39  const tab = await BrowserTestUtils.openNewForegroundTab(
     40    gBrowser,
     41    "https://example.com/browser/testing/mochitest/tests/browser/file_xorigin_frames.html"
     42  );
     43  await SpecialPowers.spawn(tab.linkedBrowser, [], async () => {
     44    Assert.equal(
     45      await this.content.wrappedJSObject.loadedPromise,
     46      "frames_all_loaded",
     47      "All (cross-origin) frames have finished loading"
     48    );
     49  });
     50  const browsingContext = tab.linkedBrowser.browsingContext;
     51  const proc1 = browsingContext.children[0].currentWindowGlobal.domProcess;
     52  const proc2 = browsingContext.children[1].currentWindowGlobal.domProcess;
     53  Assert.equal(proc1, proc2, "The two child frames share the same process");
     54 
     55  const processBoundSpecialPowers = new SpecialPowersForProcess(scope, proc1);
     56 
     57  await SpecialPowers.spawn(tab.linkedBrowser, [], async () => {
     58    info("ContentPage.spawn: Change frame1 process");
     59    const frame1 = this.content.document.getElementById("frame1");
     60    Assert.throws(
     61      () => frame1.contentDocument.location.search,
     62      /TypeError: (can't access property "location", )?frame1.contentDocument is null/,
     63      "ContentPage.spawn: Assert, cannot read cross-origin content"
     64    );
     65    await new Promise(resolve => {
     66      frame1.onload = resolve;
     67      frame1.src = "/dummy?3";
     68    });
     69    // Verify that it is same-origin now.
     70    Assert.equal(
     71      frame1.contentDocument.location.search,
     72      "?3",
     73      "CHECK_THIS: ContentPage.spawn: Assert, frame1 is now same-origin"
     74    );
     75    info("CHECK_THIS: ContentPage.spawn: remove frame1");
     76    frame1.remove();
     77 
     78    // spawn() implementation has special logic to route Assert messages;
     79    // Prepare to check that Assert can be called after spawn() returns.
     80    this.content.assertAfterSpawnReturns = () => {
     81      Assert.ok(true, "CHECK_THIS: ContentPage.spawn: asssert after return");
     82    };
     83  });
     84 
     85  await SpecialPowers.spawn(tab.linkedBrowser, [], () => {
     86    this.content.assertAfterSpawnReturns();
     87  });
     88 
     89  Assert.equal(browsingContext.children.length, 1, "frame1 was removed");
     90 
     91  // Now frame1 has navigated (and switched processes) and removed, so if the
     92  // SpecialPowers implementation were to rely on JSWindowActor, then that
     93  // would break if we try to interact with it at this point. Check that we
     94  // can connect just fine (because JSProcessActor should be used instead).
     95  await processBoundSpecialPowers.spawn([], () => {
     96    info("CHECK_THIS: process-bound spawn: still works");
     97    Assert.equal(
     98      typeof content,
     99      "undefined",
    100      "CHECK_THIS: process-bound spawn: no content global"
    101    );
    102    // Need a shared object that outlives this SpecialPowersSandbox instance:
    103    const sharedGlobalObj = Cu.getGlobalForObject(Services);
    104    // spawn() implementation has special logic to route Assert messages;
    105    // Prepare to check that Assert can be called after spawn() returns.
    106    sharedGlobalObj.assertAfterProcessBoundSpawnReturns = () => {
    107      Assert.ok(true, "CHECK_THIS: process-bound spawn: asssert after return");
    108    };
    109  });
    110  await processBoundSpecialPowers.spawn([], () => {
    111    // Shared object that outlived the previous SpecialPowersSandbox instance:
    112    const sharedGlobalObj = Cu.getGlobalForObject(Services);
    113    sharedGlobalObj.assertAfterProcessBoundSpawnReturns();
    114    delete sharedGlobalObj.assertAfterProcessBoundSpawnReturns;
    115  });
    116  BrowserTestUtils.removeTab(tab);
    117  await processBoundSpecialPowers.destroy();
    118 
    119  Assert.throws(
    120    () => processBoundSpecialPowers.spawn([], () => {}),
    121    /this.actor is null/,
    122    "Cannot spawn after destroy()"
    123  );
    124 
    125  const observedMessages = interceptedMessages.splice(0);
    126  Assert.deepEqual(
    127    observedMessages,
    128    [
    129      `CHECK_THIS: ContentPage.spawn: Assert, frame1 is now same-origin - "?3" == "?3"`,
    130      "CHECK_THIS: ContentPage.spawn: remove frame1",
    131      "CHECK_THIS: ContentPage.spawn: asssert after return - true == true",
    132      "CHECK_THIS: process-bound spawn: still works",
    133      `CHECK_THIS: process-bound spawn: no content global - "undefined" == "undefined"`,
    134      "CHECK_THIS: process-bound spawn: asssert after return - true == true",
    135    ],
    136    "Observed calls through spawn"
    137  );
    138 });