/* 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"; /* * Target actor for all Web Extension Content Scripts running against matching * web pages defined in the extension manifest. * They are running the same thread as the page (i.e. the main thread). * * See devtools/docs/contributor/backend/actor-hierarchy.md for more details about all the targets. */ const { ThreadActor } = require("resource://devtools/server/actors/thread.js"); const { WebConsoleActor, } = require("resource://devtools/server/actors/webconsole.js"); const makeDebugger = require("resource://devtools/server/actors/utils/make-debugger.js"); const { assert } = require("resource://devtools/shared/DevToolsUtils.js"); const { SourcesManager, } = require("resource://devtools/server/actors/utils/sources-manager.js"); const { contentScriptTargetSpec, } = require("resource://devtools/shared/specs/targets/content-script.js"); const Targets = require("resource://devtools/server/actors/targets/index.js"); const Resources = require("resource://devtools/server/actors/resources/index.js"); const { BaseTargetActor, } = require("resource://devtools/server/actors/targets/base-target-actor.js"); loader.lazyRequireGetter( this, "TracerActor", "resource://devtools/server/actors/tracer.js", true ); class WebExtensionContentScriptTargetActor extends BaseTargetActor { constructor(conn, { sessionContext, contentScriptSandbox } = {}) { super(conn, Targets.TYPES.CONTENT_SCRIPT, contentScriptTargetSpec); this.threadActor = null; this.sessionContext = sessionContext; this.contentScriptSandbox = contentScriptSandbox; const metadata = Cu.getSandboxMetadata(contentScriptSandbox); this.addonId = metadata.addonId; this.innerWindowId = metadata["inner-window-id"]; // Use a debugger against a unique global this.makeDebugger = makeDebugger.bind(null, { findDebuggees: _dbg => [this.contentScriptSandbox], // Only accept the content script sandbox and nothing else. shouldAddNewGlobalAsDebuggee: () => false, }); } get isRootActor() { return false; } // This will be used by the Console actor for evaluations get targetGlobal() { return this.contentScriptSandbox; } get sourcesManager() { if (!this._sourcesManager) { assert( this.threadActor, "threadActor should exist when creating SourcesManager." ); this._sourcesManager = new SourcesManager(this.threadActor); } return this._sourcesManager; } /* * Return a Debugger instance or create one if there is none yet */ get dbg() { if (!this._dbg) { this._dbg = this.makeDebugger(); } return this._dbg; } form() { if (!this._consoleActor) { this._consoleActor = new WebConsoleActor(this.conn, this); this.manage(this._consoleActor); } if (!this.threadActor) { this.threadActor = new ThreadActor(this); this.manage(this.threadActor); } if (!this.tracerActor) { this.tracerActor = new TracerActor(this.conn, this); this.manage(this.tracerActor); } const policy = WebExtensionPolicy.getByID(this.addonId); return { actor: this.actorID, addonId: this.addonId, targetType: this.targetType, // Use the related extension as content script title // as content scripts have no name, they are just a group of JS files // running against a web page. title: policy.name, // The ID of the document against which this content script executes innerWindowId: this.innerWindowId, consoleActor: this._consoleActor.actorID, threadActor: this.threadActor.actorID, tracerActor: this.tracerActor.actorID, traits: { networkMonitor: false, // See trait description in browsing-context.js supportsTopLevelTargetFlag: false, }, }; } destroy({ isModeSwitching } = {}) { // Avoid reentrancy. We will destroy the Transport when emitting "destroyed", // which will force destroying all actors. if (this.destroying) { return; } this.destroying = true; // Unregistering watchers first is important // otherwise you might have leaks reported when running browser_browser_toolbox_netmonitor.js in debug builds Resources.unwatchAllResources(this); this.emit("destroyed", { isModeSwitching }); super.destroy(); if (this.threadActor) { this.threadActor = null; } if (this._sourcesManager) { this._sourcesManager.destroy(); this._sourcesManager = null; } if (this._dbg) { this._dbg.disable(); this._dbg = null; } } } exports.WebExtensionContentScriptTargetActor = WebExtensionContentScriptTargetActor;