summaryrefslogtreecommitdiffstats
path: root/devtools/server/actors/webconsole/utils.js
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
commit36d22d82aa202bb199967e9512281e9a53db42c9 (patch)
tree105e8c98ddea1c1e4784a60a5a6410fa416be2de /devtools/server/actors/webconsole/utils.js
parentInitial commit. (diff)
downloadfirefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz
firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'devtools/server/actors/webconsole/utils.js')
-rw-r--r--devtools/server/actors/webconsole/utils.js160
1 files changed, 160 insertions, 0 deletions
diff --git a/devtools/server/actors/webconsole/utils.js b/devtools/server/actors/webconsole/utils.js
new file mode 100644
index 0000000000..2834696944
--- /dev/null
+++ b/devtools/server/actors/webconsole/utils.js
@@ -0,0 +1,160 @@
+/* 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 CONSOLE_WORKER_IDS = (exports.CONSOLE_WORKER_IDS = new Set([
+ "SharedWorker",
+ "ServiceWorker",
+ "Worker",
+]));
+
+var WebConsoleUtils = {
+ /**
+ * Given a message, return one of CONSOLE_WORKER_IDS if it matches
+ * one of those.
+ *
+ * @return string
+ */
+ getWorkerType(message) {
+ const innerID = message?.innerID;
+ return CONSOLE_WORKER_IDS.has(innerID) ? innerID : null;
+ },
+
+ /**
+ * Gets the ID of the inner window of this DOM window.
+ *
+ * @param nsIDOMWindow window
+ * @return integer|null
+ * Inner ID for the given window, null if we can't access it.
+ */
+ getInnerWindowId(window) {
+ // Might throw with SecurityError: Permission denied to access property
+ // "windowGlobalChild" on cross-origin object.
+ try {
+ return window.windowGlobalChild.innerWindowId;
+ } catch (e) {
+ return null;
+ }
+ },
+
+ /**
+ * Recursively gather a list of inner window ids given a
+ * top level window.
+ *
+ * @param nsIDOMWindow window
+ * @return Array
+ * list of inner window ids.
+ */
+ getInnerWindowIDsForFrames(window) {
+ const innerWindowID = this.getInnerWindowId(window);
+ if (innerWindowID === null) {
+ return [];
+ }
+
+ let ids = [innerWindowID];
+
+ if (window.frames) {
+ for (let i = 0; i < window.frames.length; i++) {
+ const frame = window.frames[i];
+ ids = ids.concat(this.getInnerWindowIDsForFrames(frame));
+ }
+ }
+
+ return ids;
+ },
+
+ /**
+ * Create a grip for the given value. If the value is an object,
+ * an object wrapper will be created.
+ *
+ * @param mixed value
+ * The value you want to create a grip for, before sending it to the
+ * client.
+ * @param function objectWrapper
+ * If the value is an object then the objectWrapper function is
+ * invoked to give us an object grip. See this.getObjectGrip().
+ * @return mixed
+ * The value grip.
+ */
+ createValueGrip(value, objectWrapper) {
+ switch (typeof value) {
+ case "boolean":
+ return value;
+ case "string":
+ return objectWrapper(value);
+ case "number":
+ if (value === Infinity) {
+ return { type: "Infinity" };
+ } else if (value === -Infinity) {
+ return { type: "-Infinity" };
+ } else if (Number.isNaN(value)) {
+ return { type: "NaN" };
+ } else if (!value && 1 / value === -Infinity) {
+ return { type: "-0" };
+ }
+ return value;
+ case "undefined":
+ return { type: "undefined" };
+ case "object":
+ if (value === null) {
+ return { type: "null" };
+ }
+ // Fall through.
+ case "function":
+ case "record":
+ case "tuple":
+ return objectWrapper(value);
+ default:
+ console.error(
+ "Failed to provide a grip for value of " + typeof value + ": " + value
+ );
+ return null;
+ }
+ },
+
+ /**
+ * Remove any frames in a stack that are above a debugger-triggered evaluation
+ * and will correspond with devtools server code, which we never want to show
+ * to the user.
+ *
+ * @param array stack
+ * An array of frames, with the topmost first, and each of which has a
+ * 'filename' property.
+ * @return array
+ * An array of stack frames with any devtools server frames removed.
+ * The original array is not modified.
+ */
+ removeFramesAboveDebuggerEval(stack) {
+ const debuggerEvalFilename = "debugger eval code";
+
+ // Remove any frames for server code above the last debugger eval frame.
+ const evalIndex = stack.findIndex(({ filename }, idx, arr) => {
+ const nextFrame = arr[idx + 1];
+ return (
+ filename == debuggerEvalFilename &&
+ (!nextFrame || nextFrame.filename !== debuggerEvalFilename)
+ );
+ });
+ if (evalIndex != -1) {
+ return stack.slice(0, evalIndex + 1);
+ }
+
+ // In some cases (e.g. evaluated expression with SyntaxError), we might not have a
+ // "debugger eval code" frame but still have internal ones. If that's the case, we
+ // return null as the end user shouldn't see those frames.
+ if (
+ stack.some(
+ ({ filename }) =>
+ filename && filename.startsWith("resource://devtools/")
+ )
+ ) {
+ return null;
+ }
+
+ return stack;
+ },
+};
+
+exports.WebConsoleUtils = WebConsoleUtils;