From 36d22d82aa202bb199967e9512281e9a53db42c9 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 21:33:14 +0200 Subject: Adding upstream version 115.7.0esr. Signed-off-by: Daniel Baumann --- devtools/server/actors/resources/error-messages.js | 192 +++++++++++++++++++++ 1 file changed, 192 insertions(+) create mode 100644 devtools/server/actors/resources/error-messages.js (limited to 'devtools/server/actors/resources/error-messages.js') diff --git a/devtools/server/actors/resources/error-messages.js b/devtools/server/actors/resources/error-messages.js new file mode 100644 index 0000000000..7628d7fd6d --- /dev/null +++ b/devtools/server/actors/resources/error-messages.js @@ -0,0 +1,192 @@ +/* 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 nsIConsoleListenerWatcher = require("resource://devtools/server/actors/resources/utils/nsi-console-listener-watcher.js"); +const { + DevToolsServer, +} = require("resource://devtools/server/devtools-server.js"); +const ErrorDocs = require("resource://devtools/server/actors/errordocs.js"); +const { + createStringGrip, + makeDebuggeeValue, + createValueGripForTarget, +} = require("resource://devtools/server/actors/object/utils.js"); +const { + getActorIdForInternalSourceId, +} = require("resource://devtools/server/actors/utils/dbg-source.js"); +const { + WebConsoleUtils, +} = require("resource://devtools/server/actors/webconsole/utils.js"); + +const { + TYPES: { ERROR_MESSAGE }, +} = require("resource://devtools/server/actors/resources/index.js"); +const Targets = require("resource://devtools/server/actors/targets/index.js"); + +const { MESSAGE_CATEGORY } = require("resource://devtools/shared/constants.js"); + +const PLATFORM_SPECIFIC_CATEGORIES = [ + "XPConnect JavaScript", + "component javascript", + "chrome javascript", + "chrome registration", +]; + +class ErrorMessageWatcher extends nsIConsoleListenerWatcher { + shouldHandleMessage(targetActor, message, isCachedMessage = false) { + // The listener we use can be called either with a nsIConsoleMessage or a nsIScriptError. + // In this file, we only want to handle nsIScriptError. + if ( + // We only care about nsIScriptError + !(message instanceof Ci.nsIScriptError) || + !this.isCategoryAllowed(targetActor, message.category) || + // Block any error that was triggered by eager evaluation + message.sourceName === "debugger eager eval code" + ) { + return false; + } + + // Filter specific to CONTENT PROCESS targets + if (this.isProcessTarget(targetActor)) { + // Don't want to display cached messages from private windows. + const isCachedFromPrivateWindow = + isCachedMessage && message.isFromPrivateWindow; + if (isCachedFromPrivateWindow) { + return false; + } + + // `ContentChild` forwards all errors to the parent process (via IPC) all errors up + // the parent process and sets a `isForwardedFromContentProcess` property on them. + // Ignore these forwarded messages as the original ones will be logged either in a + // content process target (if window-less message) or frame target (if related to a window) + if (message.isForwardedFromContentProcess) { + return false; + } + + // Ignore all messages related to a given window for content process targets + // These messages will be handled by Watchers instantiated for the related frame targets + if ( + targetActor.targetType == Targets.TYPES.PROCESS && + message.innerWindowID + ) { + return false; + } + + return true; + } + + if (!message.innerWindowID) { + return false; + } + + const ids = targetActor.windows.map(window => + WebConsoleUtils.getInnerWindowId(window) + ); + return ids.includes(message.innerWindowID); + } + + /** + * Check if the given message category is allowed to be tracked or not. + * We ignore chrome-originating errors as we only care about content. + * + * @param string category + * The message category you want to check. + * @return boolean + * True if the category is allowed to be logged, false otherwise. + */ + isCategoryAllowed(targetActor, category) { + // CSS Parser errors will be handled by the CSSMessageWatcher. + if (!category || category === MESSAGE_CATEGORY.CSS_PARSER) { + return false; + } + + // We listen for everything on Process targets + if (this.isProcessTarget(targetActor)) { + return true; + } + + // Don't restrict any categories in the Browser Toolbox/Browser Console + if (targetActor.sessionContext.type == "all") { + return true; + } + + // For non-process targets in other toolboxes, we filter-out platform-specific errors. + return !PLATFORM_SPECIFIC_CATEGORIES.includes(category); + } + + /** + * Prepare an nsIScriptError to be sent to the client. + * + * @param nsIScriptError error + * The page error we need to send to the client. + * @return object + * The object you can send to the remote client. + */ + buildResource(targetActor, error) { + const stack = this.prepareStackForRemote(targetActor, error.stack); + let lineText = error.sourceLine; + if ( + lineText && + lineText.length > DevToolsServer.LONG_STRING_INITIAL_LENGTH + ) { + lineText = lineText.substr(0, DevToolsServer.LONG_STRING_INITIAL_LENGTH); + } + + const notesArray = this.prepareNotesForRemote(targetActor, error.notes); + + // If there is no location information in the error but we have a stack, + // fill in the location with the first frame on the stack. + let { sourceName, sourceId, lineNumber, columnNumber } = error; + if (!sourceName && !sourceId && !lineNumber && !columnNumber && stack) { + sourceName = stack[0].filename; + sourceId = stack[0].sourceId; + lineNumber = stack[0].lineNumber; + columnNumber = stack[0].columnNumber; + } + + const pageError = { + errorMessage: createStringGrip(targetActor, error.errorMessage), + errorMessageName: error.errorMessageName, + exceptionDocURL: ErrorDocs.GetURL(error), + sourceName, + sourceId: getActorIdForInternalSourceId(targetActor, sourceId), + lineText, + lineNumber, + columnNumber, + category: error.category, + innerWindowID: error.innerWindowID, + timeStamp: error.microSecondTimeStamp / 1000, + warning: !!(error.flags & error.warningFlag), + error: !(error.flags & (error.warningFlag | error.infoFlag)), + info: !!(error.flags & error.infoFlag), + private: error.isFromPrivateWindow, + stacktrace: stack, + notes: notesArray, + chromeContext: error.isFromChromeContext, + isPromiseRejection: error.isPromiseRejection, + isForwardedFromContentProcess: error.isForwardedFromContentProcess, + }; + + // If the pageError does have an exception object, we want to return the grip for it, + // but only if we do manage to get the grip, as we're checking the property on the + // client to render things differently. + if (error.hasException) { + try { + const obj = makeDebuggeeValue(targetActor, error.exception); + if (obj?.class !== "DeadObject") { + pageError.exception = createValueGripForTarget(targetActor, obj); + pageError.hasException = true; + } + } catch (e) {} + } + + return { + pageError, + resourceType: ERROR_MESSAGE, + }; + } +} +module.exports = ErrorMessageWatcher; -- cgit v1.2.3