diff options
Diffstat (limited to '')
-rw-r--r-- | devtools/shared/transport/child-transport.js | 124 |
1 files changed, 124 insertions, 0 deletions
diff --git a/devtools/shared/transport/child-transport.js b/devtools/shared/transport/child-transport.js new file mode 100644 index 0000000000..735d5e1d08 --- /dev/null +++ b/devtools/shared/transport/child-transport.js @@ -0,0 +1,124 @@ +/* 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 flags = require("resource://devtools/shared/flags.js"); + +/** + * A transport for the debugging protocol that uses nsIMessageManagers to + * exchange packets with servers running in child processes. + * + * In the parent process, |mm| should be the nsIMessageSender for the + * child process. In a child process, |mm| should be the child process + * message manager, which sends packets to the parent. + * + * |prefix| is a string included in the message names, to distinguish + * multiple servers running in the same child process. + * + * This transport exchanges messages named 'debug:<prefix>:packet', where + * <prefix> is |prefix|, whose data is the protocol packet. + */ +function ChildDebuggerTransport(mm, prefix) { + this._mm = mm; + this._messageName = "debug:" + prefix + ":packet"; +} + +/* + * To avoid confusion, we use 'message' to mean something that + * nsIMessageSender conveys, and 'packet' to mean a remote debugging + * protocol packet. + */ +ChildDebuggerTransport.prototype = { + constructor: ChildDebuggerTransport, + + hooks: null, + + _addListener() { + this._mm.addMessageListener(this._messageName, this); + }, + + _removeListener() { + try { + this._mm.removeMessageListener(this._messageName, this); + } catch (e) { + if (e.result != Cr.NS_ERROR_NULL_POINTER) { + throw e; + } + // In some cases, especially when using messageManagers in non-e10s mode, we reach + // this point with a dead messageManager which only throws errors but does not + // seem to indicate in any other way that it is dead. + } + }, + + ready() { + this._addListener(); + }, + + close(options) { + this._removeListener(); + if (this.hooks.onTransportClosed) { + this.hooks.onTransportClosed(null, options); + } + }, + + receiveMessage({ data }) { + this.hooks.onPacket(data); + }, + + /** + * Helper method to ensure a given `object` can be sent across message manager + * without being serialized to JSON. + * See https://searchfox.org/mozilla-central/rev/6bfadf95b4a6aaa8bb3b2a166d6c3545983e179a/dom/base/nsFrameMessageManager.cpp#458-469 + */ + _canBeSerialized(object) { + try { + const holder = new StructuredCloneHolder(object); + holder.deserialize(this); + } catch (e) { + return false; + } + return true; + }, + + pathToUnserializable(object) { + for (const key in object) { + const value = object[key]; + if (!this._canBeSerialized(value)) { + if (typeof value == "object") { + return [key].concat(this.pathToUnserializable(value)); + } + return [key]; + } + } + return []; + }, + + send(packet) { + if (flags.testing && !this._canBeSerialized(packet)) { + const attributes = this.pathToUnserializable(packet); + let msg = + "Following packet can't be serialized: " + JSON.stringify(packet); + msg += "\nBecause of attributes: " + attributes.join(", ") + "\n"; + msg += "Did you pass a function or an XPCOM object in it?"; + throw new Error(msg); + } + try { + this._mm.sendAsyncMessage(this._messageName, packet); + } catch (e) { + if (e.result != Cr.NS_ERROR_NULL_POINTER) { + throw e; + } + // In some cases, especially when using messageManagers in non-e10s mode, we reach + // this point with a dead messageManager which only throws errors but does not + // seem to indicate in any other way that it is dead. + } + }, + + startBulkSend() { + throw new Error("Can't send bulk data to child processes."); + }, +}; + +exports.ChildDebuggerTransport = ChildDebuggerTransport; |