Remote Debugging Protocol Stream Transport
The Mozilla debugging protocol is specified in terms of packets exchanged between a client and server, where each packet is either a JSON text or a block of bytes (a "bulk data" packet). The protocol does not specify any particular mechanism for carrying packets from one party to the other. Implementations may choose whatever transport they like, as long as packets arrive reliably, undamaged, and in order.
This page describes the Mozilla Remote Debugging Protocol Stream Transport, a transport layer suitable for carrying Mozilla debugging protocol packets over a reliable, ordered byte stream, like a TCP/IP stream or a pipe. Debugger user interfaces can use it to exchange packets with debuggees in other processes (say, for debugging Firefox chrome code), or on other machines (say, for debugging Firefox OS apps running on a phone or tablet).
Once the underlying byte stream is established, transport participants may immediately begin sending packets, using the forms described here. The transport requires no initial handshake or setup, and no shutdown exchange: the first bytes on the stream in each direction are those of the first packet, if any; the last bytes on the stream in each direction are the final bytes of the last packet sent, if any.
The transport defines two types of packets: JSON and bulk data.
A JSON packet has the form:
where length is a series of decimal ASCII digits, JSON is a well-formed JSON text (as defined in RFC 4627) encoded in UTF-8, and length, interpreted as a number, is the length of JSON in bytes.
Bulk Data Packets
A bulk data packet has the form:
bulk actor type length:data
- The keyword
bulkis encoded in ASCII, and the spaces are always exactly one ASCII space
- actor is a sequence of Unicode characters, encoded in UTF-8, containing no spaces or colons
- type is a sequence of Unicode characters, encoded in UTF-8, containing no spaces or colons
- length is a sequence of decimal ASCII digits
- data is a sequence of bytes whose length is length interpreted as a number
The actor field is the name of the actor sending or receiving the packet. (Actors are server-side entities, so if the packet was sent by the client, actor names the recipient; and if the packet was sent by the server, actor names the sender.) The protocol imposes the same syntactic restrictions on actor names that we require here.
Which actor names are valid at any given point in an exchange is established by the remote debugging protocol.
The type field defines the type of the packet, which may be used with the actor name to route the packet to its destination properly. The protocol provides more detail about the type, which remains in effect here.
The content of a bulk data packet is exactly the sequence of bytes appearing as data. Data is not UTF-8 text.
The Stream Transport requires the underlying stream to have the following properties:
- It must be transparent: each transmitted byte is carried to the recipient without modification. Bytes whose values are ASCII control characters or fall outside the range of ASCII altogether must be carried unchanged; line terminators are left alone.
- It must be reliable: every transmitted byte makes it to the recipient, or else the connection is dropped altogether. Errors introduced by hardware, say, must be detected and corrected, or at least reported (and the connection dropped). The Stream Transport includes no checksums of its own; those are the stream's responsibility. (So, for example, a plain serial line is not suitable for use as an underlying stream.)
- It must be ordered: bytes are received in the same order they are transmitted, and bytes are not duplicated. (UDP packets, for example, may be duplicated or arrive out of order.)
TCP/IP streams and USB streams meet these requirements.
Constant-Overhead Bulk Data
In our implementation of this Stream Transport, when a participant wishes to transmit a bulk data packet, it provides the actor name, the type, the data's length in bytes, and a callback function. When the underlying stream is ready to send more data, the transport writes the packet's
bulk actor type length: header, and then passes the underlying
nsIOutputStream to the callback, which then writes the packet's data portion directly to the stream. Similarly, when a participant receives a bulk data packet, the transport parses the header, and then passes the actor name, type, and the transport's underlying
nsIInputStream to a callback function, which consumes the data directly. Thus, while the callback functions may well use fixed-size buffers to send and receive data, the transport imposes no overhead proportional to the full size of the data.