tor-browser

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

fetchSourceMap.js (4347B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
      4 
      5 "use strict";
      6 
      7 const {
      8  networkRequest,
      9 } = require("resource://devtools/client/shared/source-map-loader/utils/network-request");
     10 
     11 const {
     12  SourceMapConsumer,
     13 } = require("resource://devtools/client/shared/vendor/source-map/source-map.js");
     14 const {
     15  getSourceMap,
     16  setSourceMap,
     17 } = require("resource://devtools/client/shared/source-map-loader/utils/sourceMapRequests");
     18 const {
     19  WasmRemap,
     20 } = require("resource://devtools/client/shared/source-map-loader/utils/wasmRemap");
     21 const {
     22  convertToJSON,
     23 } = require("resource://devtools/client/shared/source-map-loader/wasm-dwarf/convertToJSON");
     24 
     25 // URLs which have been seen in a completed source map request.
     26 const originalURLs = new Set();
     27 
     28 function clearOriginalURLs() {
     29  originalURLs.clear();
     30 }
     31 
     32 function hasOriginalURL(url) {
     33  return originalURLs.has(url);
     34 }
     35 
     36 function resolveSourceMapURL(source) {
     37  let { sourceMapBaseURL, sourceMapURL } = source;
     38  sourceMapBaseURL = sourceMapBaseURL || "";
     39  sourceMapURL = sourceMapURL || "";
     40 
     41  if (!sourceMapBaseURL) {
     42    // If the source doesn't have a URL, don't resolve anything.
     43    return { resolvedSourceMapURL: sourceMapURL, baseURL: sourceMapURL };
     44  }
     45 
     46  let resolvedString;
     47  let baseURL;
     48 
     49  // When the sourceMap is a data: URL, fall back to using the source's URL,
     50  // if possible. We don't use `new URL` here because it will be _very_ slow
     51  // for large inlined source-maps, and we don't actually need to parse them.
     52  if (sourceMapURL.startsWith("data:")) {
     53    resolvedString = sourceMapURL;
     54    baseURL = sourceMapBaseURL;
     55  } else {
     56    resolvedString = new URL(
     57      sourceMapURL,
     58      // If the URL is a data: URL, the sourceMapURL needs to be absolute, so
     59      // we might as well pass `undefined` to avoid parsing a potentially
     60      // very large data: URL for no reason.
     61      sourceMapBaseURL.startsWith("data:") ? undefined : sourceMapBaseURL
     62    ).toString();
     63    baseURL = resolvedString;
     64  }
     65 
     66  return { resolvedSourceMapURL: resolvedString, baseURL };
     67 }
     68 
     69 async function _fetch(generatedSource, resolvedSourceMapURL, baseURL) {
     70  let fetched = await networkRequest(resolvedSourceMapURL, {
     71    loadFromCache: false,
     72    // Blocking redirects on the sourceMappingUrl as its not easy to verify if the
     73    // redirect protocol matches the supported ones.
     74    allowRedirects: false,
     75    sourceMapBaseURL: generatedSource.sourceMapBaseURL,
     76  });
     77 
     78  if (fetched.isDwarf) {
     79    fetched = { content: await convertToJSON(fetched.content) };
     80  }
     81 
     82  // Create the source map and fix it up.
     83  let map = await new SourceMapConsumer(fetched.content, baseURL);
     84 
     85  if (generatedSource.isWasm) {
     86    map = new WasmRemap(map);
     87    // Check if experimental scope info exists.
     88    if (fetched.content.includes("x-scopes")) {
     89      const parsedJSON = JSON.parse(fetched.content);
     90      map.xScopes = parsedJSON["x-scopes"];
     91    }
     92  }
     93 
     94  // Extend the default map object with sourceMapBaseURL, used to check further
     95  // network requests made for this sourcemap.
     96  map.sourceMapBaseURL = generatedSource.sourceMapBaseURL;
     97 
     98  if (map && map.sources) {
     99    map.sources.forEach(url => originalURLs.add(url));
    100  }
    101 
    102  return map;
    103 }
    104 
    105 function fetchSourceMap(generatedSource, resolvedSourceMapURL, baseURL) {
    106  const existingRequest = getSourceMap(generatedSource.id);
    107 
    108  // If it has already been requested, return the request. Make sure
    109  // to do this even if sourcemapping is turned off, because
    110  // pretty-printing uses sourcemaps.
    111  //
    112  // An important behavior here is that if it's in the middle of
    113  // requesting it, all subsequent calls will block on the initial
    114  // request.
    115  if (existingRequest) {
    116    return existingRequest;
    117  }
    118 
    119  if (!generatedSource.sourceMapURL) {
    120    return null;
    121  }
    122 
    123  // Fire off the request, set it in the cache, and return it.
    124  const req = _fetch(generatedSource, resolvedSourceMapURL, baseURL);
    125  // Make sure the cached promise does not reject, because we only
    126  // want to report the error once.
    127  setSourceMap(
    128    generatedSource.id,
    129    req.catch(() => null)
    130  );
    131  return req;
    132 }
    133 
    134 module.exports = {
    135  fetchSourceMap,
    136  hasOriginalURL,
    137  clearOriginalURLs,
    138  resolveSourceMapURL,
    139 };