tor-browser

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

importScripts_3rdParty_worker.js (4366B)


      1 const workerURL =
      2  "http://mochi.test:8888/tests/dom/workers/test/importScripts_3rdParty_worker.js";
      3 
      4 /**
      5 * An Error can be a JS Error or a DOMException.  The primary difference is that
      6 * JS Errors have a SpiderMonkey specific `fileName` for the filename and
      7 * DOMEXCEPTION uses `filename`.
      8 */
      9 function normalizeError(err) {
     10  if (!err) {
     11    return null;
     12  }
     13 
     14  const isDOMException = "filename" in err;
     15 
     16  return {
     17    message: err.message,
     18    name: err.name,
     19    isDOMException,
     20    code: err.code,
     21    // normalize to fileName
     22    fileName: isDOMException ? err.filename : err.fileName,
     23    hasFileName: !!err.fileName,
     24    hasFilename: !!err.filename,
     25    lineNumber: err.lineNumber,
     26    columnNumber: err.columnNumber,
     27    stack: err.stack,
     28    stringified: err.toString(),
     29  };
     30 }
     31 
     32 function normalizeErrorEvent(event) {
     33  if (!event) {
     34    return null;
     35  }
     36 
     37  return {
     38    message: event.message,
     39    filename: event.filename,
     40    lineno: event.lineno,
     41    colno: event.colno,
     42    error: normalizeError(event.error),
     43    stringified: event.toString(),
     44  };
     45 }
     46 
     47 /**
     48 * Normalize the `OnErrorEventHandlerNonNull onerror` invocation.  The
     49 * special handling in JSEventHandler::HandleEvent ends up spreading out the
     50 * contents of the ErrorEvent into discrete arguments.  The one thing lost is
     51 * we can't toString the ScriptEvent itself, but this should be the same as the
     52 * message anyways.
     53 *
     54 * The spec for the invocation is the "special error event handling" logic
     55 * described in step 4 at:
     56 * https://html.spec.whatwg.org/multipage/webappapis.html#the-event-handler-processing-algorithm
     57 * noting that the step somewhat glosses over that it's only "onerror" that is
     58 * OnErrorEventHandlerNonNull and capable of processing 5 arguments and that's
     59 * why an addEventListener "error" listener doesn't get this handling.
     60 *
     61 * Argument names here are made to match the call-site in JSEventHandler.
     62 */
     63 function normalizeOnError(
     64  msgOrEvent,
     65  fileName,
     66  lineNumber,
     67  columnNumber,
     68  error
     69 ) {
     70  return {
     71    message: msgOrEvent,
     72    filename: fileName,
     73    lineno: lineNumber,
     74    colno: columnNumber,
     75    error: normalizeError(error),
     76    stringified: null,
     77  };
     78 }
     79 
     80 /**
     81 * Helper to postMessage the provided data after a setTimeout(0) so that any
     82 * error event currently being dispatched that will bubble to our parent will
     83 * be delivered before our postMessage.
     84 */
     85 function delayedPostMessage(data) {
     86  setTimeout(() => {
     87    postMessage(data);
     88  }, 0);
     89 }
     90 
     91 onmessage = function (a) {
     92  const args = a.data;
     93  // Messages are either nested (forward to a nested worker) or should be
     94  // processed locally.
     95  if (a.data.nested) {
     96    const worker = new Worker(workerURL);
     97    let firstErrorEvent;
     98 
     99    // When the test mode is "catch"
    100 
    101    worker.onmessage = function (event) {
    102      delayedPostMessage({
    103        nestedMessage: event.data,
    104        errorEvent: firstErrorEvent,
    105      });
    106    };
    107 
    108    worker.onerror = function (event) {
    109      firstErrorEvent = normalizeErrorEvent(event);
    110      event.preventDefault();
    111    };
    112 
    113    a.data.nested = false;
    114    worker.postMessage(a.data);
    115    return;
    116  }
    117 
    118  // Local test.
    119  if (a.data.mode === "catch") {
    120    try {
    121      importScripts(a.data.url);
    122      workerMethod();
    123    } catch (ex) {
    124      delayedPostMessage({
    125        args,
    126        error: normalizeError(ex),
    127      });
    128    }
    129  } else if (a.data.mode === "uncaught") {
    130    const onerrorPromise = new Promise(resolve => {
    131      self.onerror = (...onerrorArgs) => {
    132        resolve(normalizeOnError(...onerrorArgs));
    133      };
    134    });
    135    const listenerPromise = new Promise(resolve => {
    136      self.addEventListener("error", evt => {
    137        resolve(normalizeErrorEvent(evt));
    138      });
    139    });
    140 
    141    Promise.all([onerrorPromise, listenerPromise]).then(
    142      ([onerrorEvent, listenerEvent]) => {
    143        delayedPostMessage({
    144          args,
    145          onerrorEvent,
    146          listenerEvent,
    147        });
    148      }
    149    );
    150 
    151    importScripts(a.data.url);
    152    workerMethod();
    153    // we will have thrown by this point, which will trigger an "error" event
    154    // on our global and then will propagate to our parent (which could be a
    155    // window or a worker, if nested).
    156    //
    157    // To avoid hangs, throw a different error here that will fail equivalence
    158    // tests.
    159    throw new Error("We expected an error and this is a failsafe for hangs.");
    160  }
    161 };