content-script.js (4939B)
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 /* 8 * Target actor for all Web Extension Content Scripts running against matching 9 * web pages defined in the extension manifest. 10 * They are running the same thread as the page (i.e. the main thread). 11 * 12 * See devtools/docs/contributor/backend/actor-hierarchy.md for more details about all the targets. 13 */ 14 15 const { ThreadActor } = require("resource://devtools/server/actors/thread.js"); 16 const { 17 WebConsoleActor, 18 } = require("resource://devtools/server/actors/webconsole.js"); 19 const makeDebugger = require("resource://devtools/server/actors/utils/make-debugger.js"); 20 const { assert } = require("resource://devtools/shared/DevToolsUtils.js"); 21 const { 22 SourcesManager, 23 } = require("resource://devtools/server/actors/utils/sources-manager.js"); 24 const { 25 contentScriptTargetSpec, 26 } = require("resource://devtools/shared/specs/targets/content-script.js"); 27 const Targets = require("resource://devtools/server/actors/targets/index.js"); 28 const Resources = require("resource://devtools/server/actors/resources/index.js"); 29 const { 30 BaseTargetActor, 31 } = require("resource://devtools/server/actors/targets/base-target-actor.js"); 32 33 loader.lazyRequireGetter( 34 this, 35 "TracerActor", 36 "resource://devtools/server/actors/tracer.js", 37 true 38 ); 39 40 class WebExtensionContentScriptTargetActor extends BaseTargetActor { 41 constructor(conn, { sessionContext, contentScriptSandbox } = {}) { 42 super(conn, Targets.TYPES.CONTENT_SCRIPT, contentScriptTargetSpec); 43 44 this.threadActor = null; 45 this.sessionContext = sessionContext; 46 this.contentScriptSandbox = contentScriptSandbox; 47 const metadata = Cu.getSandboxMetadata(contentScriptSandbox); 48 this.addonId = metadata.addonId; 49 this.innerWindowId = metadata["inner-window-id"]; 50 51 // Use a debugger against a unique global 52 this.makeDebugger = makeDebugger.bind(null, { 53 findDebuggees: _dbg => [this.contentScriptSandbox], 54 55 // Only accept the content script sandbox and nothing else. 56 shouldAddNewGlobalAsDebuggee: () => false, 57 }); 58 } 59 60 get isRootActor() { 61 return false; 62 } 63 64 // This will be used by the Console actor for evaluations 65 get targetGlobal() { 66 return this.contentScriptSandbox; 67 } 68 69 get sourcesManager() { 70 if (!this._sourcesManager) { 71 assert( 72 this.threadActor, 73 "threadActor should exist when creating SourcesManager." 74 ); 75 this._sourcesManager = new SourcesManager(this.threadActor); 76 } 77 return this._sourcesManager; 78 } 79 80 /* 81 * Return a Debugger instance or create one if there is none yet 82 */ 83 get dbg() { 84 if (!this._dbg) { 85 this._dbg = this.makeDebugger(); 86 } 87 return this._dbg; 88 } 89 90 form() { 91 if (!this._consoleActor) { 92 this._consoleActor = new WebConsoleActor(this.conn, this); 93 this.manage(this._consoleActor); 94 } 95 96 if (!this.threadActor) { 97 this.threadActor = new ThreadActor(this); 98 this.manage(this.threadActor); 99 } 100 if (!this.tracerActor) { 101 this.tracerActor = new TracerActor(this.conn, this); 102 this.manage(this.tracerActor); 103 } 104 105 const policy = WebExtensionPolicy.getByID(this.addonId); 106 107 return { 108 actor: this.actorID, 109 addonId: this.addonId, 110 targetType: this.targetType, 111 112 // Use the related extension as content script title 113 // as content scripts have no name, they are just a group of JS files 114 // running against a web page. 115 title: policy.name, 116 117 // The ID of the document against which this content script executes 118 innerWindowId: this.innerWindowId, 119 120 consoleActor: this._consoleActor.actorID, 121 threadActor: this.threadActor.actorID, 122 tracerActor: this.tracerActor.actorID, 123 124 traits: { 125 networkMonitor: false, 126 // See trait description in browsing-context.js 127 supportsTopLevelTargetFlag: false, 128 }, 129 }; 130 } 131 132 destroy({ isModeSwitching } = {}) { 133 // Avoid reentrancy. We will destroy the Transport when emitting "destroyed", 134 // which will force destroying all actors. 135 if (this.destroying) { 136 return; 137 } 138 this.destroying = true; 139 140 // Unregistering watchers first is important 141 // otherwise you might have leaks reported when running browser_browser_toolbox_netmonitor.js in debug builds 142 Resources.unwatchAllResources(this); 143 144 this.emit("destroyed", { isModeSwitching }); 145 146 super.destroy(); 147 148 if (this.threadActor) { 149 this.threadActor = null; 150 } 151 152 if (this._sourcesManager) { 153 this._sourcesManager.destroy(); 154 this._sourcesManager = null; 155 } 156 157 if (this._dbg) { 158 this._dbg.disable(); 159 this._dbg = null; 160 } 161 } 162 } 163 164 exports.WebExtensionContentScriptTargetActor = 165 WebExtensionContentScriptTargetActor;