--- a/devtools/server/actors/network-monitor.js
+++ b/devtools/server/actors/network-monitor.js
@@ -23,94 +23,90 @@ const NetworkMonitorActor = ActorClassWi
*
* @param object filters
* Contains an `outerWindowID` attribute when this is used across processes.
* Or a `window` attribute when instanciated in the same process.
* @param number parentID (optional)
* To be removed, specify the ID of the Web console actor.
* This is used to fake emitting an event from it to prevent changing RDP
* behavior.
- * @param nsIMessageManager messageManager (optional)
- * Passed only when it is instanciated across processes. This is the manager to
- * use to communicate with the other process.
- * @param object stackTraceCollector (optional)
- * When the actor runs in the same process than the requests we are inspecting,
- * the web console actor hands over a shared instance to the stack trace
- * collector.
+ * @param nsIMessageManager messageManager
+ * This is the manager to use to communicate with the console actor. When both
+ * netmonitor and console actor runs in the same process, this is an instance
+ * of MockMessageManager instead of a real message manager.
*/
- initialize(conn, filters, parentID, messageManager, stackTraceCollector) {
+ initialize(conn, filters, parentID, messageManager) {
Actor.prototype.initialize.call(this, conn);
this.parentID = parentID;
this.messageManager = messageManager;
- this.stackTraceCollector = stackTraceCollector;
// Immediately start watching for new request according to `filters`.
// NetworkMonitor will call `onNetworkEvent` method.
this.netMonitor = new NetworkMonitor(filters, this);
this.netMonitor.init();
- if (this.messageManager) {
- this.stackTraces = new Set();
- this.onStackTraceAvailable = this.onStackTraceAvailable.bind(this);
- this.messageManager.addMessageListener("debug:request-stack-available",
- this.onStackTraceAvailable);
- this.onRequestContent = this.onRequestContent.bind(this);
- this.messageManager.addMessageListener("debug:request-content",
- this.onRequestContent);
- this.onSetPreference = this.onSetPreference.bind(this);
- this.messageManager.addMessageListener("debug:netmonitor-preference",
- this.onSetPreference);
- this.onGetNetworkEventActor = this.onGetNetworkEventActor.bind(this);
- this.messageManager.addMessageListener("debug:get-network-event-actor",
- this.onGetNetworkEventActor);
- this.destroy = this.destroy.bind(this);
- this.messageManager.addMessageListener("debug:destroy-network-monitor",
- this.destroy);
+ this.stackTraces = new Set();
+ this.onStackTraceAvailable = this.onStackTraceAvailable.bind(this);
+ this.messageManager.addMessageListener("debug:request-stack-available",
+ this.onStackTraceAvailable);
+ this.onRequestContent = this.onRequestContent.bind(this);
+ this.messageManager.addMessageListener("debug:request-content",
+ this.onRequestContent);
+ this.onSetPreference = this.onSetPreference.bind(this);
+ this.messageManager.addMessageListener("debug:netmonitor-preference",
+ this.onSetPreference);
+ this.onGetNetworkEventActor = this.onGetNetworkEventActor.bind(this);
+ this.messageManager.addMessageListener("debug:get-network-event-actor",
+ this.onGetNetworkEventActor);
+ this.onDestroyMessage = this.onDestroyMessage.bind(this);
+ this.messageManager.addMessageListener("debug:destroy-network-monitor",
+ this.onDestroyMessage);
+ },
+
+ onDestroyMessage({ data }) {
+ if (data.actorID == this.parentID) {
+ this.destroy();
}
},
destroy() {
Actor.prototype.destroy.call(this);
if (this.netMonitor) {
this.netMonitor.destroy();
this.netMonitor = null;
}
+ this.stackTraces.clear();
if (this.messageManager) {
- this.stackTraces.clear();
this.messageManager.removeMessageListener("debug:request-stack-available",
this.onStackTraceAvailable);
this.messageManager.removeMessageListener("debug:request-content",
this.onRequestContent);
this.messageManager.removeMessageListener("debug:netmonitor-preference",
this.onSetPreference);
this.messageManager.removeMessageListener("debug:get-network-event-actor",
this.onGetNetworkEventActor);
this.messageManager.removeMessageListener("debug:destroy-network-monitor",
- this.destroy);
+ this.onDestroyMessage);
this.messageManager = null;
}
},
onStackTraceAvailable(msg) {
const { channelId } = msg.data;
if (!msg.data.stacktrace) {
this.stackTraces.delete(channelId);
} else {
this.stackTraces.add(channelId);
}
},
- getRequestContentForURL(url) {
- const actor = this._networkEventActorsByURL.get(url);
- if (!actor) {
- return null;
- }
+ getRequestContentForActor(actor) {
const content = actor._response.content;
if (actor._discardResponseBody || actor._truncated || !content || !content.size) {
// Do not return the stylesheet text if there is no meaningful content or if it's
// still loading. Let the caller handle it by doing its own separate request.
return null;
}
if (content.text.type != "longString") {
@@ -128,17 +124,20 @@ const NetworkMonitorActor = ActorClassWi
return {
content: longStringActor.str,
contentType: content.mimeType,
};
},
onRequestContent(msg) {
const { url } = msg.data;
- const content = this.getRequestContentForURL(url);
+ const actor = this._networkEventActorsByURL.get(url);
+ // Always reply with a message, but with a null `content` if this instance
+ // did not processed this request
+ const content = actor ? this.getRequestContentForActor(actor) : null;
this.messageManager.sendAsyncMessage("debug:request-content", {
url,
content,
});
},
onSetPreference({ data }) {
if ("saveRequestAndResponseBodies" in data) {
@@ -146,17 +145,20 @@ const NetworkMonitorActor = ActorClassWi
}
if ("throttleData" in data) {
this.netMonitor.throttleData = data.throttleData;
}
},
onGetNetworkEventActor({ data }) {
const actor = this.getNetworkEventActor(data.channelId);
- this.messageManager.sendAsyncMessage("debug:get-network-event-actor", actor.form());
+ this.messageManager.sendAsyncMessage("debug:get-network-event-actor", {
+ channelId: data.channelId,
+ actor: actor.form()
+ });
},
getNetworkEventActor(channelId) {
let actor = this._netEvents.get(channelId);
if (actor) {
return actor;
}
@@ -170,23 +172,19 @@ const NetworkMonitorActor = ActorClassWi
// This method is called by NetworkMonitor instance when a new request is fired
onNetworkEvent(event) {
const { channelId } = event;
const actor = this.getNetworkEventActor(channelId);
this._netEvents.set(channelId, actor);
- if (this.messageManager) {
- event.cause.stacktrace = this.stackTraces.has(channelId);
- if (event.cause.stacktrace) {
- this.stackTraces.delete(channelId);
- }
- } else {
- event.cause.stacktrace = this.stackTraceCollector.getStackTrace(channelId);
+ event.cause.stacktrace = this.stackTraces.has(channelId);
+ if (event.cause.stacktrace) {
+ this.stackTraces.delete(channelId);
}
actor.init(event);
this._networkEventActorsByURL.set(actor._request.url, actor);
const packet = {
from: this.parentID,
type: "networkEvent",
--- a/devtools/server/actors/webconsole.js
+++ b/devtools/server/actors/webconsole.js
@@ -25,16 +25,17 @@ loader.lazyRequireGetter(this, "StackTra
loader.lazyRequireGetter(this, "JSPropertyProvider", "devtools/shared/webconsole/js-property-provider", true);
loader.lazyRequireGetter(this, "Parser", "resource://devtools/shared/Parser.jsm", true);
loader.lazyRequireGetter(this, "NetUtil", "resource://gre/modules/NetUtil.jsm", true);
loader.lazyRequireGetter(this, "WebConsoleCommands", "devtools/server/actors/webconsole/utils", true);
loader.lazyRequireGetter(this, "addWebConsoleCommands", "devtools/server/actors/webconsole/utils", true);
loader.lazyRequireGetter(this, "formatCommand", "devtools/server/actors/webconsole/commands", true);
loader.lazyRequireGetter(this, "isCommand", "devtools/server/actors/webconsole/commands", true);
loader.lazyRequireGetter(this, "validCommands", "devtools/server/actors/webconsole/commands", true);
+loader.lazyRequireGetter(this, "createMessageManagerMocks", "devtools/server/actors/webconsole/message-manager-mock", true);
loader.lazyRequireGetter(this, "CONSOLE_WORKER_IDS", "devtools/server/actors/webconsole/utils", true);
loader.lazyRequireGetter(this, "WebConsoleUtils", "devtools/server/actors/webconsole/utils", true);
loader.lazyRequireGetter(this, "EnvironmentActor", "devtools/server/actors/environment", true);
loader.lazyRequireGetter(this, "EventEmitter", "devtools/shared/event-emitter");
// Overwrite implemented listeners for workers so that we don't attempt
// to load an unsupported module.
if (isWorker) {
@@ -320,32 +321,23 @@ WebConsoleActor.prototype =
/**
* Destroy the current WebConsoleActor instance.
*/
destroy() {
if (this.consoleServiceListener) {
this.consoleServiceListener.destroy();
this.consoleServiceListener = null;
}
- if (this.networkMonitorActor) {
- this.networkMonitorActor.destroy();
- this.networkMonitorActor = null;
- }
- if (this.networkMonitorActorId) {
- const messageManager = this.parentActor.messageManager;
- if (messageManager) {
+ if (this.netmonitors) {
+ for (const { messageManager } of this.netmonitors) {
messageManager.sendAsyncMessage("debug:destroy-network-monitor", {
- actorId: this.networkMonitorActorId
+ actorID: this.actorID
});
}
- this.networkMonitorActorId = null;
- }
- if (this.networkMonitorChildActor) {
- this.networkMonitorChildActor.destroy();
- this.networkMonitorChildActor = null;
+ this.netmonitors = null;
}
if (this.consoleAPIListener) {
this.consoleAPIListener.destroy();
this.consoleAPIListener = null;
}
if (this.stackTraceCollector) {
this.stackTraceCollector.destroy();
this.stackTraceCollector = null;
@@ -584,30 +576,16 @@ WebConsoleActor.prototype =
* @param object request
* The JSON request object received from the Web Console client.
* @return object
* The response object which holds the startedListeners array.
*/
startListeners: async function(request) {
const startedListeners = [];
const window = !this.parentActor.isRootActor ? this.window : null;
- let messageManager = null;
-
- // Check if the actor is running in a child process (but only if
- // Services.appinfo exists, to prevent startListeners to fail
- // when the target is a Worker).
- const processBoundary = Services.appinfo && (
- Services.appinfo.processType != Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT
- );
-
- // Retrieve a message manager from the parent actor if this actor is
- // not currently running in the main process.
- if (processBoundary) {
- messageManager = this.parentActor.messageManager;
- }
while (request.listeners.length > 0) {
const listener = request.listeners.shift();
switch (listener) {
case "PageError":
// Workers don't support this message type yet
if (isWorker) {
break;
@@ -629,48 +607,79 @@ WebConsoleActor.prototype =
}
startedListeners.push(listener);
break;
case "NetworkActivity":
// Workers don't support this message type
if (isWorker) {
break;
}
- if (!this.networkMonitorActorId && !this.networkMonitorActor) {
- // Create a StackTraceCollector that's going to be shared both by
- // the NetworkMonitorActor running in the same process for service worker
- // requests, as well with the NetworkMonitorActor running in the parent
- // process. It will communicate via message manager for this one.
- this.stackTraceCollector = new StackTraceCollector({ window },
- messageManager);
- this.stackTraceCollector.init();
+ if (!this.netmonitors) {
+ // Instanciate fake message managers used for service worker's netmonitor
+ // when running in the content process, and for netmonitor running in the
+ // same process when running in the parent process.
+ // `createMessageManagerMocks` returns a couple of connected messages
+ // managers that pass messages to each other to simulate the process
+ // boundary. We will use the first one for the webconsole-actor and the
+ // second one will be used by the netmonitor-actor.
+ const [ mmMockParent, mmMockChild ] = createMessageManagerMocks();
- if (messageManager && processBoundary) {
+ // Maintain the list of message manager we should message to/listen from
+ // to support the netmonitor instances, also records actorID of each
+ // NetworkMonitorActor.
+ // Array of `{ messageManager, parentProcess }`.
+ // Where `parentProcess` is true for the netmonitor actor instanciated in the
+ // parent process.
+ this.netmonitors = [];
+
+ // Check if the actor is running in a content process
+ const isInContentProcess =
+ Services.appinfo.processType != Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT &&
+ this.parentActor.messageManager;
+ if (isInContentProcess) {
// Start a network monitor in the parent process to listen to
- // most requests than happen in parent
- this.networkMonitorActorId = await this.conn.spawnActorInParentProcess(
+ // most requests that happen in parent. This one will communicate through
+ // `messageManager`.
+ await this.conn.spawnActorInParentProcess(
this.actorID, {
module: "devtools/server/actors/network-monitor",
constructor: "NetworkMonitorActor",
args: [
{ outerWindowID: this.parentActor.outerWindowID },
this.actorID
],
});
+ this.netmonitors.push({
+ messageManager: this.parentActor.messageManager,
+ parentProcess: true
+ });
+ }
- // Spawn also one in the child to listen to service workers
- this.networkMonitorChildActor = new NetworkMonitorActor(this.conn,
- { window },
- this.actorID,
- null,
- this.stackTraceCollector);
- } else {
- this.networkMonitorActor = new NetworkMonitorActor(this.conn, { window },
- this.actorID, null, this.stackTraceCollector);
- }
+ // When the console actor runs in the parent process, Netmonitor can be ran
+ // in the process and communicate through `messageManagerMock`.
+ // And while it runs in the content process, we also spawn one in the content
+ // to listen to requests that happen in the content process (for instance
+ // service workers requests)
+ new NetworkMonitorActor(this.conn,
+ { window },
+ this.actorID,
+ mmMockParent);
+
+ this.netmonitors.push({
+ messageManager: mmMockChild,
+ parentProcess: !isInContentProcess
+ });
+
+ // Create a StackTraceCollector that's going to be shared both by
+ // the NetworkMonitorActor running in the same process for service worker
+ // requests, as well with the NetworkMonitorActor running in the parent
+ // process. It will communicate via message manager for this one.
+ this.stackTraceCollector = new StackTraceCollector({ window },
+ this.netmonitors);
+ this.stackTraceCollector.init();
}
startedListeners.push(listener);
break;
case "FileActivity":
// Workers don't support this message type
if (isWorker) {
break;
}
@@ -759,32 +768,23 @@ WebConsoleActor.prototype =
case "ConsoleAPI":
if (this.consoleAPIListener) {
this.consoleAPIListener.destroy();
this.consoleAPIListener = null;
}
stoppedListeners.push(listener);
break;
case "NetworkActivity":
- if (this.networkMonitorActor) {
- this.networkMonitorActor.destroy();
- this.networkMonitorActor = null;
- }
- if (this.networkMonitorActorId) {
- const messageManager = this.parentActor.messageManager;
- if (messageManager) {
+ if (this.netmonitors) {
+ for (const { messageManager } of this.netmonitors) {
messageManager.sendAsyncMessage("debug:destroy-network-monitor", {
- actorId: this.networkMonitorActorId
+ actorID: this.actorID
});
}
- this.networkMonitorActorId = null;
- }
- if (this.networkMonitorChildActor) {
- this.networkMonitorChildActor.destroy();
- this.networkMonitorChildActor = null;
+ this.netmonitors = null;
}
if (this.stackTraceCollector) {
this.stackTraceCollector.destroy();
this.stackTraceCollector = null;
}
stoppedListeners.push(listener);
break;
case "FileActivity":
@@ -1246,41 +1246,29 @@ WebConsoleActor.prototype =
*
* @param object request
* The request message - which preferences need to be updated.
*/
setPreferences: function(request) {
for (const key in request.preferences) {
this._prefs[key] = request.preferences[key];
- if (key == "NetworkMonitor.saveRequestAndResponseBodies") {
- if (this.networkMonitorActor) {
- this.networkMonitorActor.netMonitor.saveRequestAndResponseBodies =
- this._prefs[key];
- }
- if (this.networkMonitorChildActor) {
- this.networkMonitorChildActor.netMonitor.saveRequestAndResponseBodies =
- this._prefs[key];
- }
- if (this.networkMonitorActorId) {
- const messageManager = this.parentActor.messageManager;
- messageManager.sendAsyncMessage("debug:netmonitor-preference",
- { saveRequestAndResponseBodies: this._prefs[key] });
- }
- } else if (key == "NetworkMonitor.throttleData") {
- if (this.networkMonitorActor) {
- this.networkMonitorActor.netMonitor.throttleData = this._prefs[key];
- }
- if (this.networkMonitorChildActor) {
- this.networkMonitorChildActor.netMonitor.throttleData = this._prefs[key];
- }
- if (this.networkMonitorActorId) {
- const messageManager = this.parentActor.messageManager;
- messageManager.sendAsyncMessage("debug:netmonitor-preference",
- { throttleData: this._prefs[key] });
+ if (this.netmonitors) {
+ if (key == "NetworkMonitor.saveRequestAndResponseBodies") {
+ for (const { messageManager } of this.netmonitors) {
+ messageManager.sendAsyncMessage("debug:netmonitor-preference", {
+ saveRequestAndResponseBodies: this._prefs[key]
+ });
+ }
+ } else if (key == "NetworkMonitor.throttleData") {
+ for (const { messageManager } of this.netmonitors) {
+ messageManager.sendAsyncMessage("debug:netmonitor-preference", {
+ throttleData: this._prefs[key]
+ });
+ }
}
}
}
return { updated: Object.keys(request.preferences) };
},
// End of request handlers.
@@ -1812,36 +1800,40 @@ WebConsoleActor.prototype =
* Get the NetworkEventActor for a given URL that may have been noticed by the network
* listener. Requests are added when they start, so the actor might not yet have all
* data for the request until it has completed.
*
* @param string url
* The URL of the request to search for.
*/
getRequestContentForURL(url) {
- // When running in Parent Process, call the NetworkMonitorActor directly.
- if (this.networkMonitorActor) {
- return this.networkMonitorActor.getRequestContentForURL(url);
- } else if (this.networkMonitorActorId) {
- // Otherwise, if the netmonitor is started, but on the parent process,
- // pipe the data through the message manager
- const messageManager = this.parentActor.messageManager;
- return new Promise(resolve => {
- const onMessage = ({ data }) => {
- if (data.url == url) {
+ if (!this.netmonitors) {
+ return null;
+ }
+ return new Promise(resolve => {
+ let messagesReceived = 0;
+ const onMessage = ({ data }) => {
+ if (data.url != url) {
+ return;
+ }
+ messagesReceived++;
+ // Either use the first response with a content, or return a null content
+ // if we received the responses from all the message managers.
+ if (data.content || messagesReceived == this.netmonitors.length) {
+ for (const { messageManager } of this.netmonitors) {
messageManager.removeMessageListener("debug:request-content", onMessage);
- resolve(data.content);
}
- };
+ resolve(data.content);
+ }
+ };
+ for (const { messageManager } of this.netmonitors) {
messageManager.addMessageListener("debug:request-content", onMessage);
messageManager.sendAsyncMessage("debug:request-content", { url });
- });
- }
- // Finally, if the netmonitor is not started at all, return null
- return null;
+ }
+ });
},
/**
* Send a new HTTP request from the target's window.
*
* @param object message
* Object with 'request' - the HTTP request details.
*/
@@ -1877,40 +1869,38 @@ WebConsoleActor.prototype =
const bodyStream = Cc["@mozilla.org/io/string-input-stream;1"]
.createInstance(Ci.nsIStringInputStream);
bodyStream.setData(body, body.length);
channel.explicitSetUploadStream(bodyStream, null, -1, method, false);
}
NetUtil.asyncFetch(channel, () => {});
- // When running in Parent Process, call the NetworkMonitorActor directly.
+ if (!this.netmonitors) {
+ return null;
+ }
const { channelId } = channel;
- if (this.networkMonitorActor) {
- const actor = this.networkMonitorActor.getNetworkEventActor(channelId);
- return {
- eventActor: actor.form()
- };
- } else if (this.networkMonitorActorId) {
- // Otherwise, if the netmonitor is started, but on the parent process,
- // pipe the data through the message manager
- const messageManager = this.parentActor.messageManager;
- return new Promise(resolve => {
- const onMessage = ({ data }) => {
+ // Only query the NetworkMonitorActor running in the parent process, where the
+ // request will be done. There always is one listener running in the parent process,
+ // see startListeners.
+ const netmonitor = this.netmonitors.filter(({ parentProcess }) => parentProcess)[0];
+ const { messageManager } = netmonitor;
+ return new Promise(resolve => {
+ const onMessage = ({ data }) => {
+ if (data.channelId == channelId) {
messageManager.removeMessageListener("debug:get-network-event-actor",
onMessage);
resolve({
- eventActor: data
+ eventActor: data.actor
});
- };
- messageManager.addMessageListener("debug:get-network-event-actor", onMessage);
- messageManager.sendAsyncMessage("debug:get-network-event-actor", { channelId });
- });
- }
- return null;
+ }
+ };
+ messageManager.addMessageListener("debug:get-network-event-actor", onMessage);
+ messageManager.sendAsyncMessage("debug:get-network-event-actor", { channelId });
+ });
},
/**
* Handler for file activity. This method sends the file request information
* to the remote Web Console client.
*
* @see ConsoleProgressListener
* @param string fileURI
new file mode 100644
--- /dev/null
+++ b/devtools/server/actors/webconsole/message-manager-mock.js
@@ -0,0 +1,68 @@
+/* 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";
+
+/**
+ * Implements a fake MessageManager class that allows to use the message
+ * manager API within the same process. This implementation will forward
+ * messages within the same process.
+ *
+ * It helps having the same codepath for actors being evaluated in the same
+ * process *and* in a remote one.
+ */
+function MessageManagerMock() {
+ this._listeners = new Map();
+}
+MessageManagerMock.prototype = {
+ addMessageListener(name, listener) {
+ let listeners = this._listeners.get(name);
+ if (!listeners) {
+ listeners = [];
+ this._listeners.set(name, listeners);
+ }
+ if (!listeners.includes(listener)) {
+ listeners.push(listener);
+ }
+ },
+ removeMessageListener(name, listener) {
+ const listeners = this._listeners.get(name);
+ const idx = listeners.indexOf(listener);
+ listeners.splice(idx, 1);
+ },
+ sendAsyncMessage(name, data) {
+ this.other.internalSendAsyncMessage(name, data);
+ },
+ internalSendAsyncMessage(name, data) {
+ const listeners = this._listeners.get(name);
+ if (!listeners) {
+ return;
+ }
+ const message = {
+ target: this,
+ data
+ };
+ for (const listener of listeners) {
+ if (typeof listener === "object" &&
+ typeof listener.receiveMessage === "function") {
+ listener.receiveMessage(message);
+ } else if (typeof listener === "function") {
+ listener(message);
+ }
+ }
+ },
+};
+
+/**
+ * Create two MessageManager mocks, connected to each others.
+ * Calling sendAsyncMessage on the first will dispatch messages on the second one,
+ * and the other way around
+ */
+exports.createMessageManagerMocks = function() {
+ const a = new MessageManagerMock();
+ const b = new MessageManagerMock();
+ a.other = b;
+ b.other = a;
+ return [a, b];
+};
--- a/devtools/server/actors/webconsole/moz.build
+++ b/devtools/server/actors/webconsole/moz.build
@@ -3,12 +3,13 @@
# 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/.
DevToolsModules(
'commands.js',
'content-process-forward.js',
'listeners.js',
+ 'message-manager-mock.js',
'screenshot.js',
'utils.js',
'worker-listeners.js',
)
--- a/devtools/shared/webconsole/network-monitor.js
+++ b/devtools/shared/webconsole/network-monitor.js
@@ -172,43 +172,43 @@ ChannelEventSinkFactory.unregister = fun
ChannelEventSinkFactory.getService = function() {
// Make sure the ChannelEventSink service is registered before accessing it
ChannelEventSinkFactory.register();
return Cc[SINK_CONTRACT_ID].getService(Ci.nsIChannelEventSink).wrappedJSObject;
};
-function StackTraceCollector(filters, messageManager) {
+function StackTraceCollector(filters, netmonitors) {
this.filters = filters;
this.stacktracesById = new Map();
- this.messageManager = messageManager;
+ this.netmonitors = netmonitors;
}
StackTraceCollector.prototype = {
init() {
Services.obs.addObserver(this, "http-on-opening-request");
ChannelEventSinkFactory.getService().registerCollector(this);
- if (this.messageManager) {
- this.onGetStack = this.onGetStack.bind(this);
- this.messageManager.addMessageListener("debug:request-stack", this.onGetStack);
+ this.onGetStack = this.onGetStack.bind(this);
+ for (const { messageManager } of this.netmonitors) {
+ messageManager.addMessageListener("debug:request-stack", this.onGetStack);
}
},
destroy() {
Services.obs.removeObserver(this, "http-on-opening-request");
ChannelEventSinkFactory.getService().unregisterCollector(this);
- if (this.messageManager) {
- this.messageManager.removeMessageListener("debug:request-stack", this.onGetStack);
+ for (const { messageManager } of this.netmonitors) {
+ messageManager.removeMessageListener("debug:request-stack", this.onGetStack);
}
},
_saveStackTrace(channel, stacktrace) {
- if (this.messageManager) {
- this.messageManager.sendAsyncMessage("debug:request-stack-available", {
+ for (const { messageManager } of this.netmonitors) {
+ messageManager.sendAsyncMessage("debug:request-stack-available", {
channelId: channel.channelId,
stacktrace: stacktrace && stacktrace.length > 0
});
}
this.stacktracesById.set(channel.channelId, stacktrace);
},
observe(subject) {
@@ -258,19 +258,20 @@ StackTraceCollector.prototype = {
getStackTrace(channelId) {
const trace = this.stacktracesById.get(channelId);
this.stacktracesById.delete(channelId);
return trace;
},
onGetStack(msg) {
+ const messageManager = msg.target;
const channelId = msg.data;
const stack = this.getStackTrace(channelId);
- this.messageManager.sendAsyncMessage("debug:request-stack", {
+ messageManager.sendAsyncMessage("debug:request-stack", {
channelId,
stack,
});
},
};
exports.StackTraceCollector = StackTraceCollector;