summaryrefslogtreecommitdiffstats
path: root/devtools/server/actors/watcher/session-context.js
blob: 6457399455675b2998ca9cb2bdecbe48baf656c5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
/* 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";

// Module to create all the Session Context objects.
//
// These are static JSON serializable object that help describe
// the debugged context. It is passed around to most of the server codebase
// in order to know which object to consider inspecting and communicating back to the client.
//
// These objects are all instantiated by the Descriptor actors
// and passed as a constructor argument to the Watcher actor.
//
// These objects have attributes used by all the Session contexts:
// - type: String
//   Describes which type of context we are debugging.
//   See SESSION_TYPES for all possible values.
//   See each create* method for more info about each type and their specific attributes.
// - isServerTargetSwitchingEnabled: Boolean
//   If true, targets should all be spawned by the server codebase.
//   Especially the first, top level target.
// - supportedTargets: Boolean
//   An object keyed by target type, whose value indicates if we have watcher support
//   for the target.
// - supportedResources: Boolean
//   An object keyed by resource type, whose value indicates if we have watcher support
//   for the resource.

const Targets = require("resource://devtools/server/actors/targets/index.js");
const Resources = require("resource://devtools/server/actors/resources/index.js");

const SESSION_TYPES = {
  ALL: "all",
  BROWSER_ELEMENT: "browser-element",
  CONTENT_PROCESS: "content-process",
  WEBEXTENSION: "webextension",
  WORKER: "worker",
};

/**
 * Create the SessionContext used by the Browser Toolbox and Browser Console.
 *
 * This context means debugging everything.
 * The whole browser:
 * - all processes: parent and content,
 * - all privileges: privileged/chrome and content/web,
 * - all components/targets: HTML documents, processes, workers, add-ons,...
 */
function createBrowserSessionContext() {
  const type = SESSION_TYPES.ALL;

  return {
    type,
    // For now, the top level target (ParentProcessTargetActor) is created via ProcessDescriptor.getTarget
    // and is never replaced by any other, nor is it created by the WatcherActor.
    isServerTargetSwitchingEnabled: false,
    supportedTargets: getWatcherSupportedTargets(type),
    supportedResources: getWatcherSupportedResources(type),
  };
}

/**
 * Create the SessionContext used by the regular web page toolboxes as well as remote debugging android device tabs.
 *
 * @param {BrowserElement} browserElement
 *        The tab to debug. It should be a reference to a <browser> element.
 * @param {Object} config
 *        An object with optional configuration. Only supports "isServerTargetSwitchingEnabled" attribute.
 *        See jsdoc in this file header for more info.
 */
function createBrowserElementSessionContext(browserElement, config) {
  const type = SESSION_TYPES.BROWSER_ELEMENT;
  return {
    type,
    browserId: browserElement.browserId,
    // Nowaday, it should always be enabled except for WebExtension special
    // codepath and some tests.
    isServerTargetSwitchingEnabled: config.isServerTargetSwitchingEnabled,
    // Should we instantiate targets for popups opened in distinct tabs/windows?
    // Driven by devtools.popups.debug=true preference.
    isPopupDebuggingEnabled: config.isPopupDebuggingEnabled,
    supportedTargets: getWatcherSupportedTargets(type),
    supportedResources: getWatcherSupportedResources(type),
  };
}

/**
 * Create the SessionContext used by the web extension toolboxes.
 *
 * @param {Object} addon
 *        First object argument to describe the add-on.
 * @param {String} addon.addonId
 *        The web extension ID, to uniquely identify the debugged add-on.
 * @param {String} addon.browsingContextID
 *        The ID of the BrowsingContext into which this add-on is loaded.
 *        For now the top level target is associated with this one precise BrowsingContext.
 *        Knowing about it later helps associate resources to the same BrowsingContext ID and so the same target.
 * @param {String} addon.innerWindowId
 *        The ID of the WindowGlobal into which this add-on is loaded.
 *        This is used for the same reason as browsingContextID. It helps match the resource with the right target.
 *        We now also use the WindowGlobal ID/innerWindowId to identify the targets.
 * @param {Object} config
 *        An object with optional configuration. Only supports "isServerTargetSwitchingEnabled" attribute.
 *        See jsdoc in this file header for more info.
 */
function createWebExtensionSessionContext(
  { addonId, browsingContextID, innerWindowId },
  config
) {
  const type = SESSION_TYPES.WEBEXTENSION;
  return {
    type,
    addonId,
    addonBrowsingContextID: browsingContextID,
    addonInnerWindowId: innerWindowId,
    // For now, there is only one target (WebExtensionTargetActor), it is never replaced,
    // and is only created via WebExtensionDescriptor.getTarget (and never by the watcher actor).
    isServerTargetSwitchingEnabled: config.isServerTargetSwitchingEnabled,
    supportedTargets: getWatcherSupportedTargets(type),
    supportedResources: getWatcherSupportedResources(type),
  };
}

/**
 * Create the SessionContext used by the Browser Content Toolbox, to debug only one content process.
 * Or when debugging XpcShell via about:debugging, where we instantiate only one content process target.
 */
function createContentProcessSessionContext() {
  const type = SESSION_TYPES.CONTENT_PROCESS;
  return {
    type,
    supportedTargets: getWatcherSupportedTargets(type),
    supportedResources: getWatcherSupportedResources(type),
  };
}

/**
 * Create the SessionContext used when debugging one specific Service Worker or special chrome worker.
 * This is only used from about:debugging.
 */
function createWorkerSessionContext() {
  const type = SESSION_TYPES.WORKER;
  return {
    type,
    supportedTargets: getWatcherSupportedTargets(type),
    supportedResources: getWatcherSupportedResources(type),
  };
}

/**
 * Get the supported targets by the watcher given a session context type.
 *
 * @param {String} type
 * @returns {Object}
 */
function getWatcherSupportedTargets(type) {
  return {
    [Targets.TYPES.FRAME]: true,
    [Targets.TYPES.PROCESS]: true,
    [Targets.TYPES.WORKER]:
      type == SESSION_TYPES.BROWSER_ELEMENT ||
      type == SESSION_TYPES.WEBEXTENSION,
    [Targets.TYPES.SERVICE_WORKER]: type == SESSION_TYPES.BROWSER_ELEMENT,
  };
}

/**
 * Get the supported resources by the watcher given a session context type.
 *
 * @param {String} type
 * @returns {Object}
 */
function getWatcherSupportedResources(type) {
  // All resources types are supported for tab debugging and web extensions.
  // Some watcher classes are still disabled for the Multiprocess Browser Toolbox (type=SESSION_TYPES.ALL).
  // And they may also be disabled for workers once we start supporting them by the watcher.
  // So set the traits to false for all the resources that we don't support yet
  // and keep using the legacy listeners.
  const isTabOrWebExtensionToolbox =
    type == SESSION_TYPES.BROWSER_ELEMENT || type == SESSION_TYPES.WEBEXTENSION;

  return {
    [Resources.TYPES.CONSOLE_MESSAGE]: true,
    [Resources.TYPES.CSS_CHANGE]: isTabOrWebExtensionToolbox,
    [Resources.TYPES.CSS_MESSAGE]: true,
    [Resources.TYPES.CSS_REGISTERED_PROPERTIES]: true,
    [Resources.TYPES.DOCUMENT_EVENT]: true,
    [Resources.TYPES.CACHE_STORAGE]: true,
    [Resources.TYPES.COOKIE]: true,
    [Resources.TYPES.ERROR_MESSAGE]: true,
    [Resources.TYPES.EXTENSION_STORAGE]: true,
    [Resources.TYPES.INDEXED_DB]: true,
    [Resources.TYPES.LOCAL_STORAGE]: true,
    [Resources.TYPES.SESSION_STORAGE]: true,
    [Resources.TYPES.PLATFORM_MESSAGE]: true,
    [Resources.TYPES.NETWORK_EVENT]: true,
    [Resources.TYPES.NETWORK_EVENT_STACKTRACE]: true,
    [Resources.TYPES.REFLOW]: true,
    [Resources.TYPES.STYLESHEET]: true,
    [Resources.TYPES.SOURCE]: true,
    [Resources.TYPES.THREAD_STATE]: true,
    [Resources.TYPES.SERVER_SENT_EVENT]: true,
    [Resources.TYPES.WEBSOCKET]: true,
    [Resources.TYPES.JSTRACER_TRACE]: true,
    [Resources.TYPES.JSTRACER_STATE]: true,
    [Resources.TYPES.LAST_PRIVATE_CONTEXT_EXIT]: true,
  };
}

module.exports = {
  createBrowserSessionContext,
  createBrowserElementSessionContext,
  createWebExtensionSessionContext,
  createContentProcessSessionContext,
  createWorkerSessionContext,
  SESSION_TYPES,
};