forked from mirrors/gecko-dev
Backed out changeset 0965e956200a (bug 1834725) Backed out changeset 4a8151163607 (bug 1834725) Backed out changeset a56f42223377 (bug 1834725) Backed out changeset a920356b63eb (bug 1834725)
137 lines
4.2 KiB
JavaScript
137 lines
4.2 KiB
JavaScript
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
|
|
|
|
"use strict";
|
|
|
|
const {
|
|
networkRequest,
|
|
} = require("resource://devtools/client/shared/source-map-loader/utils/network-request");
|
|
|
|
const {
|
|
SourceMapConsumer,
|
|
} = require("resource://devtools/client/shared/vendor/source-map/source-map.js");
|
|
const {
|
|
getSourceMap,
|
|
setSourceMap,
|
|
} = require("resource://devtools/client/shared/source-map-loader/utils/sourceMapRequests");
|
|
const {
|
|
WasmRemap,
|
|
} = require("resource://devtools/client/shared/source-map-loader/utils/wasmRemap");
|
|
const {
|
|
convertToJSON,
|
|
} = require("resource://devtools/client/shared/source-map-loader/wasm-dwarf/convertToJSON");
|
|
|
|
// URLs which have been seen in a completed source map request.
|
|
const originalURLs = new Set();
|
|
|
|
function clearOriginalURLs() {
|
|
originalURLs.clear();
|
|
}
|
|
|
|
function hasOriginalURL(url) {
|
|
return originalURLs.has(url);
|
|
}
|
|
|
|
function _resolveSourceMapURL(source) {
|
|
let { sourceMapBaseURL, sourceMapURL } = source;
|
|
sourceMapBaseURL = sourceMapBaseURL || "";
|
|
sourceMapURL = sourceMapURL || "";
|
|
|
|
if (!sourceMapBaseURL) {
|
|
// If the source doesn't have a URL, don't resolve anything.
|
|
return { sourceMapURL, baseURL: sourceMapURL };
|
|
}
|
|
|
|
let resolvedString;
|
|
let baseURL;
|
|
|
|
// When the sourceMap is a data: URL, fall back to using the source's URL,
|
|
// if possible. We don't use `new URL` here because it will be _very_ slow
|
|
// for large inlined source-maps, and we don't actually need to parse them.
|
|
if (sourceMapURL.startsWith("data:")) {
|
|
resolvedString = sourceMapURL;
|
|
baseURL = sourceMapBaseURL;
|
|
} else {
|
|
resolvedString = new URL(
|
|
sourceMapURL,
|
|
// If the URL is a data: URL, the sourceMapURL needs to be absolute, so
|
|
// we might as well pass `undefined` to avoid parsing a potentially
|
|
// very large data: URL for no reason.
|
|
sourceMapBaseURL.startsWith("data:") ? undefined : sourceMapBaseURL
|
|
).toString();
|
|
baseURL = resolvedString;
|
|
}
|
|
|
|
return { sourceMapURL: resolvedString, baseURL };
|
|
}
|
|
|
|
async function _resolveAndFetch(generatedSource) {
|
|
// Fetch the sourcemap over the network and create it.
|
|
const { sourceMapURL, baseURL } = _resolveSourceMapURL(generatedSource);
|
|
|
|
let fetched = await networkRequest(sourceMapURL, {
|
|
loadFromCache: false,
|
|
// Blocking redirects on the sourceMappingUrl as its not easy to verify if the
|
|
// redirect protocol matches the supported ones.
|
|
allowRedirects: false,
|
|
sourceMapBaseURL: generatedSource.sourceMapBaseURL,
|
|
});
|
|
|
|
if (fetched.isDwarf) {
|
|
fetched = { content: await convertToJSON(fetched.content) };
|
|
}
|
|
|
|
// Create the source map and fix it up.
|
|
let map = await new SourceMapConsumer(fetched.content, baseURL);
|
|
|
|
if (generatedSource.isWasm) {
|
|
map = new WasmRemap(map);
|
|
// Check if experimental scope info exists.
|
|
if (fetched.content.includes("x-scopes")) {
|
|
const parsedJSON = JSON.parse(fetched.content);
|
|
map.xScopes = parsedJSON["x-scopes"];
|
|
}
|
|
}
|
|
|
|
// Extend the default map object with sourceMapBaseURL, used to check further
|
|
// network requests made for this sourcemap.
|
|
map.sourceMapBaseURL = generatedSource.sourceMapBaseURL;
|
|
|
|
if (map && map.sources) {
|
|
map.sources.forEach(url => originalURLs.add(url));
|
|
}
|
|
|
|
return map;
|
|
}
|
|
|
|
function fetchSourceMap(generatedSource) {
|
|
const existingRequest = getSourceMap(generatedSource.id);
|
|
|
|
// If it has already been requested, return the request. Make sure
|
|
// to do this even if sourcemapping is turned off, because
|
|
// pretty-printing uses sourcemaps.
|
|
//
|
|
// An important behavior here is that if it's in the middle of
|
|
// requesting it, all subsequent calls will block on the initial
|
|
// request.
|
|
if (existingRequest) {
|
|
return existingRequest;
|
|
}
|
|
|
|
if (!generatedSource.sourceMapURL) {
|
|
return null;
|
|
}
|
|
|
|
// Fire off the request, set it in the cache, and return it.
|
|
const req = _resolveAndFetch(generatedSource);
|
|
// Make sure the cached promise does not reject, because we only
|
|
// want to report the error once.
|
|
setSourceMap(
|
|
generatedSource.id,
|
|
req.catch(() => null)
|
|
);
|
|
return req;
|
|
}
|
|
|
|
module.exports = { fetchSourceMap, hasOriginalURL, clearOriginalURLs };
|