forked from Mirrors/freeswitch
3abb7730b2
git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@3772 d0543943-73ff-0310-b7d9-9358b9ac24b2
339 lines
12 KiB
Plaintext
339 lines
12 KiB
Plaintext
This is a draft, and subject to change. Please do not implement it
|
|
yet. Thank you!
|
|
|
|
Examples can be found at the bottom of the file.
|
|
|
|
Thank you for your feedback!
|
|
|
|
Eric Kidd
|
|
eric.kidd@pobox.com
|
|
30 January 2001
|
|
|
|
|
|
The Binmode RPC Protocol
|
|
========================
|
|
|
|
Binmode RPC is an ultra-lightweight RPC protocol designed for 100%
|
|
compatibility with XML-RPC <http://www.xmlrpc.com/>. It emphasizes
|
|
simplicity, dynamically-typed data, and extreme ease of implementation.
|
|
|
|
Two XML-RPC implementations that support 'binmode-rpc' may negotiate away
|
|
the XML part of XML-RPC, and replace it with a simple binary protocol.
|
|
|
|
Design goals:
|
|
|
|
* The complete specification should fit in a 350-line text file. :-)
|
|
* The protocol should be easy to implement.
|
|
* The protocol should provide a high degree of compression.
|
|
* The protocol should be very fast--faster than zlib compression.
|
|
* The protocol must be implementable in portable ANSI C, with no
|
|
'./configure' checks.
|
|
* The protocol must not contain any options, variant encodings
|
|
or similar hair. If you want DCE/RPC, you know where to find it.
|
|
* All protocol operations must be performed at the byte level
|
|
(except for UTF-8 encoding and decoding).
|
|
* The protocol must be semi-readable in a hex dump or Emacs buffer.
|
|
* The protocol must efficiently encode boxcarred calls that are
|
|
implemented using 'system.multicall'.
|
|
* The protocol must support an efficient encoding for
|
|
frequently-repeated string values.
|
|
|
|
* The protocol must never be sent to clients or servers which
|
|
don't support it.
|
|
* There must be a way for clients and servers to active the protocol
|
|
if both ends of the connection support it.
|
|
|
|
|
|
The X-XML-RPC-Extensions Header
|
|
-------------------------------
|
|
|
|
(First, we'll need a mechanism for unobtrusively announcing the presence of
|
|
non-standard capabilities.)
|
|
|
|
An XML-RPC implementation MAY advertise additional, non-standard
|
|
capabilities using the 'X-XML-RPC-Extensions' header.
|
|
|
|
Rationale: The 'X-XML-RPC-Extensions' header should be available to CGI
|
|
scripts in the environment variable HTTP_X_XML_RPC_EXTENSIONS.
|
|
|
|
If present, this header MUST contain a comma-separated list of
|
|
keywords. Parameter information MAY be included, if desired, in the
|
|
standard fashion used by HTTP 1.1 'Accept-Encoding' headers.
|
|
|
|
X-XML-RPC-Extensions: binmode-rpc
|
|
X-XML-RPC-Extensions: binmode-rpc, x-telepathic-transport
|
|
X-XML-RPC-Extensions: binmode-rpc,x-telepathic-transport
|
|
X-XML-RPC-Extensions: binmode-rpc, x-telepathic-transport;speed=low
|
|
|
|
If a client sends the X-XML-RPC-Extensions header in a request, the server
|
|
MAY use any of the specified extensions in its response.
|
|
|
|
Rationale: No client may be sent non-standard data without first having
|
|
advertised the ability to accept it.
|
|
|
|
If the server includes the X-XML-RPC-Extensions header in a response, the
|
|
client MAY use any of the specified extensions in further requests to that
|
|
URL. The client MUST NOT assume that the same extensions are available for
|
|
any other URL on the same server.
|
|
|
|
Rationale: No server may be sent non-standard data without first having
|
|
advertised the ability to accept it. Furthermore, this permission is
|
|
URL-specific, since different XML-RPC implementations may be located at
|
|
different URLs on a single server.
|
|
|
|
The client SHOULD NOT cache extension information about a particular server
|
|
for an excessive length of time (typically beyond a single program
|
|
invocation). If the client does cache this information indefinitely, it
|
|
SHOULD be able to cope if an extension is disabled.
|
|
|
|
Rationale: The XML-RPC implementation used on the server may be changed by
|
|
the administrator.
|
|
|
|
|
|
The 'binmode-rpc' Extension
|
|
-----------------------
|
|
|
|
A client or server which sends the 'binmode-rpc' extension MUST accept
|
|
message bodies of type 'application/x-binmode-rpc' in addition to the
|
|
regular 'text/xml'.
|
|
|
|
All servers which accept the binmode-rpc extension MUST also support
|
|
standard XML-RPC, as described by <http://www.xmlrpc.org/spec>.
|
|
|
|
|
|
The 'application/x-binmode-rpc' Format
|
|
--------------------------------------
|
|
|
|
All documents of the type 'application/x-binmode-rpc' MUST begin with the
|
|
following byte sequence (represented here as a C string):
|
|
|
|
'binmode-rpc:'
|
|
|
|
This MUST be followed by a Call or a Response, encoded as described below:
|
|
|
|
Call := 'C' String Array
|
|
|
|
A Call consists of a single octet with the ASCII value 'C', followed by a
|
|
String containing the method name and an Array containing the parameters.
|
|
|
|
Response := 'R' (Value|Fault)
|
|
|
|
A Response MUST contain either a Value or a Fault.
|
|
|
|
Fault := 'F' Struct
|
|
|
|
A Fault contains a regular Struct (with members as specified by the the
|
|
XML-RPC specification).
|
|
|
|
Trailing data at the end of an 'application/x-binmode-rpc' document MUST be
|
|
ignored.
|
|
|
|
|
|
Byte-Order of Integers
|
|
----------------------
|
|
|
|
(The following integer types don't correspond directly to XML-RPC
|
|
integers--instead, they'll be used to *build* more complicated types.)
|
|
|
|
SignedLSB := a four-octet, signed, twos'-complement integer,
|
|
least-significant byte (LSB) first
|
|
UnsignedLSB := a four-octet, unsigned integer, LSB first
|
|
|
|
Raw integer data is encoded in little-endian format.
|
|
|
|
Rationale: A fixed, mandatory byte ordering is easier to implement than
|
|
approaches which allow multiple byte orderings, and little-endian CPUs
|
|
outnumber big-endian CPUs at the time of writing.
|
|
|
|
|
|
Values
|
|
------
|
|
|
|
Value := (Integer|Boolean|Double|DateTimeISO8601Binary|Array|Struct|
|
|
String|Other)
|
|
|
|
Integer := 'I' SignedLSB
|
|
Boolean := ('t'|'f')
|
|
|
|
Double := 'D' SizeOctet AsciiChar...
|
|
DateTimeISO8601 := '8' SizeOctet AsciiChar...
|
|
|
|
These two types are encoded with an unsigned size octet followed by the
|
|
specified number of ASCII characters. The values are encoded in the fashion
|
|
described by the XML-RPC specification.
|
|
|
|
Rationale: In both these cases, we're punting. Binary floating point
|
|
formats are highly non-portable, and cannot be easily manipulated by most
|
|
programming languages. XML-RPC <dateTime.iso8601> values lack timezone
|
|
information, and are therefore difficult to convert to a binary format.
|
|
|
|
Binary := 'B' UnsignedLSB Octet...
|
|
|
|
This corresponds to the XML-RPC <base64> type, but without any encoding.
|
|
The UnsignedLSB specifies the number of octets of data.
|
|
|
|
Array := 'A' UnsignedLSB Value...
|
|
|
|
The UnsignedLSB specifies the number of values in the array.
|
|
|
|
Struct := 'S' UnsignedLSB (String,Value)...
|
|
|
|
The UnsignedLSB specifies the number of String,Value pairs in the struct.
|
|
The strings are keys; the values may be of any type.
|
|
|
|
Other := 'O' String Binary
|
|
|
|
Future XML-RPC types (if any) may be sent a String containing the type name
|
|
and a Binary block (as above) containing type-specific data.
|
|
Implementations MUST NOT encode any of the standard types using this
|
|
construct. Implementations MAY signal an error if data of type Other is
|
|
encountered.
|
|
|
|
Rationale: This is allowed to cause an error because most applications
|
|
won't understand the contents anyway. But if new types are added, dumb
|
|
gateways will be able to manipulate them in encapsulated format (if they so
|
|
desire).
|
|
|
|
|
|
Strings
|
|
-------
|
|
|
|
String := (RegularString|RecordedString|RecalledString)
|
|
|
|
We have three types of strings.
|
|
|
|
RegularString := 'U' StringData
|
|
StringData := UnsignedLSB Utf8Octet...
|
|
|
|
Strings are encoded in UTF-8 format. The UnsignedLSB specifies the number
|
|
of UTF-8 octets. Implementations SHOULD raise an error if they encounter
|
|
invalid UTF-8 data (e.g., ISO Latin 1 characters).
|
|
|
|
Rationale: Technically speaking, XML-RPC is limited to plain ASCII
|
|
characters, and may not contain 8-bit or 16-bit characters in any coding
|
|
system. But since XML-RPC is based on XML, adding Unicode is a trivial
|
|
enhancement to the basic protocol, and *somebody* will make it sooner or
|
|
later. When that day arrives, we want to be able to encode Unicode
|
|
characters.
|
|
|
|
Implements MUST encode UTF-8 characters using the minimum number of octets.
|
|
Implementations SHOULD raise an error if they encounter any UTF-8
|
|
characters encoded using more than the minimum number of octets.
|
|
|
|
Rationale: Overlong UTF-8 encodings are sometimes used to bypass string
|
|
validation in security code. They serve no legitimate purpose, either. So
|
|
to improve the overall security of the Universe, we work hard to discourage
|
|
them.
|
|
|
|
UTF-8 & Unicode FAQ: http://www.cl.cam.ac.uk/~mgk25/unicode.html
|
|
|
|
RecordedString := '>' CodebookPosition StringData
|
|
RecalledString := '<' CodebookPosition
|
|
CodebookPosition := UnsignedOctet
|
|
|
|
The 'binmode' format supports a 256-entry "codebook" of strings. At the
|
|
start of a data stream, the codebook is empty. When the decoder
|
|
encounters a RecordedString, it MUST store it into the specified codebook
|
|
position (and then proceed to decode it as a regular string).
|
|
|
|
When the decoder encounters a RecalledString, it MUST look it up in the
|
|
specified codebook position. If that codebook position has been set, the
|
|
implementation MUST use the string value found in the codebook. If the
|
|
position has not been set, the implementation MUST stop decoding and raise
|
|
an error. It is legal to change a codebook position once it has been set;
|
|
the most recent value applies.
|
|
|
|
A RecordedString or a RecalledString may be used anywhere a RegularString
|
|
may be used.
|
|
|
|
Rationale: XML-RPC data tends to contain large numbers of identical
|
|
strings. (These are typically the names of <struct> members or the names of
|
|
methods in a multicall.) To get any kind of reasonable data compression,
|
|
it's necessary to have some way of compressing these values. The codebook
|
|
mechanism is relatively simple and uncomplicated.
|
|
|
|
Implementations MAY choose not to use this feature when encoding data, but
|
|
MUST understand it when decoding data.
|
|
|
|
Rationale: On the decoding end of things, this feature is trivial to
|
|
implement, and must be present for the sake of interoperability. On the
|
|
encoding end of things, however, making effective use of this feature is
|
|
slightly trickier, so implementations are allowed (but not encouraged) to
|
|
omit it.
|
|
|
|
|
|
Compliance
|
|
----------
|
|
|
|
Implementations MUST implement all features of this protocol correctly,
|
|
particularly on the decoding end. In the case of this protocol, a 95% correct
|
|
implementation is 100% broken. Yes, this statement is redundant. ;-)
|
|
|
|
|
|
Examples
|
|
--------
|
|
|
|
Non-ASCII octets are specified as in C strings. Continued lines are
|
|
indicated by a trailing '\'; these should be joined together as one
|
|
sequence of bytes.
|
|
|
|
binmode-rpc:CU\003\0\0\0addA\002\0\0\0I\002\0\0\0I\002\0\0\0
|
|
|
|
binmode-rpc:RI\004\0\0\0
|
|
|
|
binmode-rpc:RFS\002\0\0\0 \
|
|
U\011\0\0\0faultCodeI\001\0\0\0 \
|
|
U\013\0\0\0faultStringU\021\0\0\0An error occurred
|
|
|
|
binmode-rpc:RA\006\0\0\0 \
|
|
>\000\003\0\0\0foo \
|
|
>\001\003\0\0\0bar \
|
|
<\000 \
|
|
>\000\003\0\0\0baz \
|
|
<\000 \
|
|
<\001
|
|
|
|
(This deserializes to ['foo', 'bar', 'foo', 'baz', 'baz', 'bar'].)
|
|
|
|
binmode-rpc:RU\042\0\0\0Copyright \302\251 1995 J. Random Hacker
|
|
|
|
(This is based on an example in the Unicode/UTF-8 FAQ (see above).)
|
|
|
|
binmode-rpc:RA\010\0\0\0 \
|
|
I\006\0\0\0 \
|
|
tf \
|
|
D\0042.75 \
|
|
8\02119980717T14:08:55 \
|
|
U\003\0\0\0foo \
|
|
B\003\0\0\0abc \
|
|
S\002\0\0\0U\003\0\0\0runt
|
|
|
|
Counter-Examples
|
|
----------------
|
|
|
|
The following specimens are illegal, and SHOULD be rejected by a compliant
|
|
implementation. Please test your code.
|
|
|
|
* A different format name:
|
|
|
|
binmode-rpc2:RI\004\0\0\0
|
|
|
|
* A built-in type incorrectly encoded using 'O':
|
|
|
|
binmode-rpc:ROU\006\0\0\0stringB\003\0\0\0xyz
|
|
|
|
* A recall of an unrecorded string:
|
|
|
|
binmode-rpc:R<\002
|
|
|
|
* ISO Latin 1 data in a string. (UTF-8 required!)
|
|
|
|
binmode-rpc:RU\041\0\0\0Copyright \251 1995 J. Random Hacker
|
|
|
|
* UTF-8 character encoded with too many octets (based on an example in the
|
|
Unicode/UTF-8 FAQ):
|
|
|
|
binmode-rpc:RU\041\0\0\0Bad linefeed: \300\212 (too many bytes)
|
|
|
|
A compliant implementation MUST NOT send any of these sequences.
|