tor-browser

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

browser_webconsole_stubs_network_event.js (6717B)


      1 /* Any copyright is dedicated to the Public Domain.
      2 * http://creativecommons.org/publicdomain/zero/1.0/ */
      3 
      4 "use strict";
      5 
      6 const {
      7  createCommandsForTab,
      8  STUBS_UPDATE_ENV,
      9  getCleanedPacket,
     10  getSerializedPacket,
     11  getStubFile,
     12  writeStubsToFile,
     13 } = require(`${CHROME_URL_ROOT}stub-generator-helpers`);
     14 
     15 const TEST_URI =
     16  "https://example.com/browser/devtools/client/webconsole/test/browser/test-network-event.html";
     17 const STUB_FILE = "networkEvent.js";
     18 
     19 add_task(async function () {
     20  const isStubsUpdate = Services.env.get(STUBS_UPDATE_ENV) == "true";
     21  info(`${isStubsUpdate ? "Update" : "Check"} ${STUB_FILE}`);
     22 
     23  const generatedStubs = await generateNetworkEventStubs();
     24 
     25  if (isStubsUpdate) {
     26    await writeStubsToFile(STUB_FILE, generatedStubs, true);
     27    ok(true, `${STUB_FILE} was updated`);
     28    return;
     29  }
     30 
     31  const existingStubs = getStubFile(STUB_FILE);
     32  const FAILURE_MSG =
     33    "The network event stubs file needs to be updated by running `" +
     34    `mach test ${getCurrentTestFilePath()} --headless --setenv WEBCONSOLE_STUBS_UPDATE=true` +
     35    "`";
     36 
     37  if (generatedStubs.size !== existingStubs.stubPackets.size) {
     38    ok(false, FAILURE_MSG);
     39    return;
     40  }
     41 
     42  let failed = false;
     43  for (const [key, packet] of generatedStubs) {
     44    // const existingPacket = existingStubs.stubPackets.get(key);
     45    const packetStr = getSerializedPacket(packet, {
     46      sortKeys: true,
     47      replaceActorIds: true,
     48    });
     49    const existingPacketStr = getSerializedPacket(
     50      existingStubs.stubPackets.get(key),
     51      { sortKeys: true, replaceActorIds: true }
     52    );
     53    is(packetStr, existingPacketStr, `"${key}" packet has expected value`);
     54    failed = failed || packetStr !== existingPacketStr;
     55  }
     56 
     57  if (failed) {
     58    ok(false, FAILURE_MSG);
     59  } else {
     60    ok(true, "Stubs are up to date");
     61  }
     62 });
     63 
     64 async function generateNetworkEventStubs() {
     65  const stubs = new Map();
     66  const tab = await addTab(TEST_URI);
     67  const commands = await createCommandsForTab(tab);
     68  await commands.targetCommand.startListening();
     69  const resourceCommand = commands.resourceCommand;
     70 
     71  const stacktraces = new Map();
     72  let addNetworkStub = function () {};
     73  let addNetworkUpdateStub = function () {};
     74 
     75  const onAvailable = resources => {
     76    for (const resource of resources) {
     77      if (resource.resourceType == resourceCommand.TYPES.NETWORK_EVENT) {
     78        if (stacktraces.has(resource.channelId)) {
     79          const { stacktraceAvailable, lastFrame } = stacktraces.get(
     80            resource.channelId
     81          );
     82          resource.cause.stacktraceAvailable = stacktraceAvailable;
     83          resource.cause.lastFrame = lastFrame;
     84          stacktraces.delete(resource.channelId);
     85        }
     86        addNetworkStub(resource);
     87        continue;
     88      }
     89      if (
     90        resource.resourceType == resourceCommand.TYPES.NETWORK_EVENT_STACKTRACE
     91      ) {
     92        stacktraces.set(resource.channelId, resource);
     93      }
     94    }
     95  };
     96  const onUpdated = updates => {
     97    for (const { resource, update } of updates) {
     98      addNetworkUpdateStub(resource, update);
     99    }
    100  };
    101 
    102  await resourceCommand.watchResources(
    103    [
    104      resourceCommand.TYPES.NETWORK_EVENT_STACKTRACE,
    105      resourceCommand.TYPES.NETWORK_EVENT,
    106    ],
    107    {
    108      onAvailable,
    109      onUpdated,
    110    }
    111  );
    112 
    113  for (const [key, code] of getCommands()) {
    114    const networkEventDone = new Promise(resolve => {
    115      addNetworkStub = resource => {
    116        stubs.set(key, getCleanedPacket(key, getOrderedResource(resource)));
    117        resolve();
    118      };
    119    });
    120 
    121    const networkEventUpdateDone = new Promise(resolve => {
    122      addNetworkUpdateStub = (resource, update) => {
    123        const updateKey = `${key} update`;
    124        stubs.set(key, getCleanedPacket(key, getOrderedResource(resource)));
    125        stubs.set(
    126          updateKey,
    127          // We cannot ensure the form of the resource, some properties
    128          // might be in another order than in the original resource.
    129          // Hand-picking only what we need should prevent this.
    130          getCleanedPacket(updateKey, getOrderedResource(resource))
    131        );
    132 
    133        if (update.resourceUpdates.responseEndAvailable) {
    134          resolve();
    135        }
    136      };
    137    });
    138 
    139    await SpecialPowers.spawn(
    140      gBrowser.selectedBrowser,
    141      [code],
    142      function (subCode) {
    143        const script = content.document.createElement("script");
    144        script.append(
    145          content.document.createTextNode(
    146            `function triggerPacket() {${subCode}}`
    147          )
    148        );
    149        content.document.body.append(script);
    150        content.wrappedJSObject.triggerPacket();
    151        script.remove();
    152      }
    153    );
    154    await Promise.all([networkEventDone, networkEventUpdateDone]);
    155  }
    156  resourceCommand.unwatchResources(
    157    [
    158      resourceCommand.TYPES.NETWORK_EVENT_STACKTRACE,
    159      resourceCommand.TYPES.NETWORK_EVENT,
    160    ],
    161    {
    162      onAvailable,
    163      onUpdated,
    164    }
    165  );
    166 
    167  await commands.destroy();
    168 
    169  return stubs;
    170 }
    171 // Ensures the order of the resource properties
    172 function getOrderedResource(resource) {
    173  return {
    174    resourceType: resource.resourceType,
    175    timeStamp: resource.timeStamp,
    176    actor: resource.actor,
    177    startedDateTime: resource.startedDateTime,
    178    method: resource.method,
    179    url: resource.url,
    180    isXHR: resource.isXHR,
    181    cause: resource.cause,
    182    httpVersion: resource.httpVersion,
    183    status: resource.status,
    184    statusText: resource.statusText,
    185    headersSize: resource.headersSize,
    186    remoteAddress: resource.remoteAddress,
    187    remotePort: resource.remotePort,
    188    mimeType: resource.mimeType,
    189    waitingTime: resource.waitingTime,
    190    contentSize: resource.contentSize,
    191    transferredSize: resource.transferredSize,
    192    timings: resource.timings,
    193    private: resource.private,
    194    fromCache: resource.fromCache,
    195    fromServiceWorker: resource.fromServiceWorker,
    196    isThirdPartyTrackingResource: resource.isThirdPartyTrackingResource,
    197    referrerPolicy: resource.referrerPolicy,
    198    blockedReason: resource.blockedReason,
    199    extension: resource.extension,
    200    channelId: resource.channelId,
    201    totalTime: resource.totalTime,
    202    securityState: resource.securityState,
    203    responseCache: resource.responseCache,
    204    isRacing: resource.isRacing,
    205  };
    206 }
    207 
    208 function getCommands() {
    209  const networkEvent = new Map();
    210 
    211  networkEvent.set(
    212    "GET request",
    213    `
    214 let i = document.createElement("img");
    215 i.src = "/inexistent.html";
    216 `
    217  );
    218 
    219  networkEvent.set(
    220    "XHR GET request",
    221    `
    222 const xhr = new XMLHttpRequest();
    223 xhr.open("GET", "/inexistent.html");
    224 xhr.send();
    225 `
    226  );
    227 
    228  networkEvent.set(
    229    "XHR POST request",
    230    `
    231 const xhr = new XMLHttpRequest();
    232 xhr.open("POST", "/inexistent.html");
    233 xhr.send();
    234 `
    235  );
    236  return networkEvent;
    237 }