Applications, restricted either by their runtime environments or by firewalls that permit only Web browsing, often find that arbitrary TCP connections (see &rfc0793;) cannot be established. BOSH, the protocol described in this document, may be used as a "drop-in" alternative to a bi-directional TCP connection. It is a mature fully-featured protocol that has been in use for many years with many open source and commercial implementations. It overcomes common communication constraints by employing fully-compliant "cookie-free"
BOSH can transport any data efficiently and with minimal latency in both directions. For applications that require both "push" and "pull" communications, BOSH is significantly more bandwidth-efficient and responsive than most other bi-directional HTTP-based transport protocols (e.g. &xep0025;) and techniques now commonly known as AJAX.
BOSH achieves this efficiency and low-latency by avoiding polling without resorting to chunked HTTP responses (i.e. without using the technique which is now commonly known as "Comet"). The protocol employs multiple synchronous HTTP request/response pairs. This technique allows it to pass through even those proxies that buffer partial HTTP responses before forwarding the full responses only once they are available.
Note: Although the XML being transported in the examples herein is XMPP, this transport is not part of XMPP. In fact, from its conception the intention of the primary author was that it could be used to implement any bidirectional XML stream transporting a mixture of elements qualified by namespaces defined by different protocols (e.g., both XMPP and JSON). This mix is necessary since some connection managers may not support Multiple Streams and constrained clients often have no access to HTTP Pipelining (which limits them to one BOSH session at a time). BOSH connection managers are generally not required to understand anything about the XML content that they transport beyond perhaps ensuring that each XML stanza is qualified by the correct namespace. &xep0206; documents some XMPP-specific extensions of this protocol that were formerly included in this document.
Note: This document inherits terminology regarding the Hypertext Transport Protocol from RFC 1945 and RFC 2616.
The following design requirements reflect the need to offer performance as close as possible to a standard TCP connection.
*Compatibility with constrained runtime environments implies the following restrictions:
This document assumes that most implementations will utilize a specialized "connection manager" to handle HTTP connections rather than the usual TCP connections. Effectively, such a connection manager will be a specialized HTTP server that translates between the HTTP requests and responses defined herein and the data streams (or API) implemented by the &server; or &server;s with which it communicates, thus enabling an HTTP client to connect to a &server;. We can illustrate this graphically as follows:
wrapper]
|
HTTP Client
]]>
BOSH addresses communications between an HTTP client and the connection manager only. It does not address communications between the connection manager and the &server;, since such communications are implementation-specific (e.g., the &server; may natively support this HTTP binding, in which case the connection manager will be a logical entity rather than a physical entity; alternatively the connection manager may be an independant translating proxy such that the &server; may believe it is talking directly to the client over TCP; or the connection manager and the &server; may use a component protocol or an API defined by the &server; implementation).
Furthermore, no aspect of this protocol limits its use to client-to-server communications. It could be used for server-to-server or component-to-server communications as well. However, this document focuses exclusively on use of the transport by clients that cannot maintain arbitrary persistent TCP connections with a server. We assume that servers and components are under no such restrictions and thus would use TCP.
Since HTTP is a synchronous request/response protocol, the traditional solution to emulating a bidirectional-stream over HTTP involved the client intermittently polling the connection manager to discover if it has any data queued for delivery to the client. This naive approach wastes a lot of network bandwidth by polling when no data is available. It also reduces the responsiveness of the application since the data spends time queued waiting until the connection manager receives the next poll (HTTP request) from the client. This results in an inevitable trade-off between responsiveness and bandwidth, since increasing the polling frequency will decrease latency but simultaneously increase bandwidth consumption (or vice versa if polling frequency is decreased).
The technique employed by this protocol achieves both low latency and low bandwidth consumption by encouraging the connection manager not to respond to a request until it actually has data to send to the client. As soon as the client receives a response from the connection manager it sends another request, thereby ensuring that the connection manager is (almost) always holding a request that it can use to "push" data to the client.
If the client needs to send some data to the connection manager then it simply sends a second request containing the data. Unfortunately most constrained clients do not support HTTP Pipelining (concurrent requests over a single connection), so the client typically needs to send the data over a second HTTP connection. The connection manager always responds to the request it has been holding on the first connection as soon as it receives a new request from the client - even if it has no data to send the client. It does that to make sure the client can send more data immediately if necessary. (The client cannot open more than two HTTP connections at the same time,
BOSH works reliably even if network conditions force every HTTP request to be made over a different TCP connection. However, if as is usually the case, the client is able to use HTTP/1.1, then (assuming reliable network conditions) all requests during a session will pass over the same two persistent connections. Almost all of the time (see below) the client is able to push data on one of the connections, while the connection manager is able to "push" data on the other (so latency is as low as a standard TCP connection). It's interesting to note that the roles of the two connections typically switch whenever the client sends data to the connection manager.
If there is no traffic in either direction for an agreed amount of time (typically a couple of minutes), then the connection manager responds to the client with no data, and that response immediately triggers a fresh client request. The connection manager does that to ensure that if a network connection is broken then both parties will realise within a reasonable amount of time. This exchange is similar to the "keep-alive" or "ping" that is common practice over most persistent TCP connections. Since the BOSH technique involves no polling, bandwidth consumption is not significantly greater than a standard TCP connection.
Most of the time data can be pushed immediately. However, if one of the endpoints has just pushed some data then it will usually have to wait for a network round trip until it is able to push again. If HTTP Pipelining is available to the client then multiple concurrent requests are possible. So the client can always push data immediately. It can also ensure the connection manager is always holding enough requests such that even during bursts of activity it will never have to wait before pushing data. Furthermore, if the pool of requests being held by the connection manager is large enough, then the client will not be under pressure to send a new empty request immediately after receiving data from the connection manager. It can instead wait until it needs to send data. So, if over time the traffic to and from the client is balanced, bandwidth consumption will be about the same as if a standard TCP connection was being used.
Each block of data pushed by the connection manager is a complete HTTP response. So, unlike the Comet technique, the BOSH technique works through intermediate proxies that buffer partial HTTP responses. It is also fully compliant with HTTP/1.0 - which does not provide for chunked transfer encoding. Also unlike Comet, Web clients can use BOSH to make cross-domain connections.
All information is encoded in the body of standard HTTP POST requests and responses. Each HTTP body contains a single <body/> wrapper which encapsulates the XML elements being transferred (see <body/> Wrapper Element).
Clients SHOULD send all HTTP requests over a single persistent HTTP/1.1 connection using HTTP Pipelining. However, a client MAY deliver its POST requests in any way permited by RFC 1945 or RFC 2616. For examples, constrained clients can be expected to open more than one persistent connection instead of using Pipelining, or in some cases to open a new HTTP/1.0 connection to send each request. However, clients and connection managers SHOULD NOT use Chunked Transfer Coding, since intermediaries may buffer each partial HTTP request or response and only forward the full request or reponse once it is available.
Clients MAY include an HTTP Accept-Encoding header in any request. If the connection manager receives a request with an Accept-Encoding header, it MAY include an HTTP Content-Encoding header in the response (indicating one of the encodings specified in the request) and compress the response body accordingly.
Requests and responses MAY include HTTP headers not specified herein. The receiver SHOULD ignore any such headers.
Each BOSH session MAY share the HTTP connection(s) it uses with other HTTP traffic, including other BOSH sessions and HTTP requests and responses completely unrelated to this protocol (e.g., web page downloads).
The HTTP Content-Type header of all client requests SHOULD be "text/xml; charset=utf-8". However, clients MAY specify another value if they are constrained to do so (e.g., "application/x-www-form-urlencoded" or "text/plain"). The client and connection manager SHOULD ignore all HTTP Content-Type headers they receive.
The body of each HTTP request and response contains a single <body/> wrapper element qualified by the 'http://jabber.org/protocol/httpbind' namespace. The content of the wrapper is the data being transfered. The <body/> element and it's content together MUST conform to the specifications set out in &w3xml;. They SHOULD also conform to &w3xmlnamespaces;. The content MUST NOT contain any of the following (all defined in XML 1.0):
Partial XML elements
XML comments
XML processing instructions
Internal or external DTD subsets
Internal or external entity references (with the exception of predefined entities)
Character data or attribute values containing unescaped characters that map to the predefined entities (such characters MUST be escaped)
The <body/> wrapper MUST NOT contain any XML character data, although its child elements MAY contain character data. The <body/> wrapper MUST contain zero or more complete XML immediate child elements (called "stanzas" in this document, e.g., XMPP stanzas, or elements containing XML character data that represents objects using the JSON data interchange format - see &rfc4627;). Each <body/> wrapper MAY contain stanzas qualified under a wide variety of different namespaces.
The <body/> element of every client request MUST possess a sequential request ID encapsulated via the 'rid' attribute; For details, refer to the Request IDs section of this document.
The first request from the client to the connection manager requests a new session.
The <body/> element of the first request SHOULD possess the following attributes (they SHOULD NOT be included in any other requests except as specified in Adding Streams To A Session):
Note: Clients that only support Polling Sessions MAY prevent the connection manager from waiting by setting 'wait' or 'hold' to "0". However, polling is NOT RECOMMENDED since the associated increase in bandwidth consumption and the decrease in responsiveness are typically one or two orders of magnitude!
A connection manager MAY be configured to enable sessions with more than one &server; in different domains. When requesting a session with such a 'proxy' connection manager, a client SHOULD include a 'route' attribute that specifies the protocol, hostname, and port of the &server; with which it wants to communicate, formatted as "proto:host:port" (e.g., "xmpp:jabber.org:9999").
A client MAY include a 'from' attribute to enable the connection manager to forward its identity to the &server;.
A client MAY include a 'secure' attribute to specify that communications between the connection manager and the &server; must be "secure". (Note: The 'secure' attribute is of type xs:boolean (see &w3xmlschema2;) and the default value is "false". &BOOLEANNOTE;) If a connection manager receives a session request with the 'secure' attribute set to "true" or "1", then it MUST respond to the client with a remote-connection-failed error as soon as it determines that it cannot communicate in a secure way with the &server;. A connection manager SHOULD consider communications with the &server; to be "secure" if they are encrypted using SSL or TLS with verified certificates, or if it is running on the same physical machine as the &server;. A connection manager MAY consider communications over a "private" network to be secure, even without SSL or TLS; however, a network SHOULD be considered "private" only if the administrator of the connection manager is sure that unknown individuals or processes do not have access to the network (i.e., individuals or processes who do not have access to either the connection manager or the &server;). The connection manager SHOULD try to establish a secure connection with the &server; even if the client does not specifically require it.
Some clients are constrained to only accept HTTP responses with specific Content-Types (e.g., "text/html"). The <body/> element of the first request MAY possess a 'content' attribute. This specifies the value of the HTTP Content-Type header that MUST appear in all the connection manager's responses during the session. If the client request does not possess a 'content' attribute, then the HTTP Content-Type header of responses MUST be "text/xml; charset=utf-8".
Note: All requests after the first one MUST include a valid 'sid' attribute (provided by the connection manager in the Session Creation Response). The initialization request is unique in that the <body/> element MUST NOT possess a 'sid' attribute.
After receiving a new session request, the connection manager MUST generate an opaque, unpredictable session identifier (or SID). The SID MUST be unique within the context of the connection manager application. The <body/> element of the connection manager's response to the client's session creation request MUST possess the following attributes (they SHOULD NOT be included in any other responses):
The <body/> element SHOULD also include the following attributes (they SHOULD NOT be included in any other responses):
The connection manager MAY include an 'accept' attribute in the session creation response element, to specify the content encodings it can decompress. After receiving a session creation response with an 'accept' attribute, clients MAY include an HTTP Content-Encoding header in subsequent requests (indicating one of the encodings specified in the 'accept' attribute) and compress the bodies of the requests accordingly.
If the connection manager supports session pausing (see Inactivity) then it SHOULD advertise that to the client by including a 'maxpause' attribute in the session creation response element. The value of the attribute indicates the maximum length of a temporary session pause (in seconds) that a client MAY request.
For both requests and responses, the <body/> element and its content SHOULD be UTF-8 encoded. If the HTTP Content-Type header of a request/response specifies a character encoding other than UTF-8, then the connection manager MAY convert between UTF-8 and the other character encoding. However, even in this case, it is OPTIONAL for the connection manager to convert between encodings. The connection manager MAY inform the client which encodings it can convert by setting the optional 'charsets' attribute in the session creation response element to a space-separated list of encodings.
As soon as the connection manager has established a connection to the &server; and discovered its identity, it MAY forward the identity to the client by including a 'from' attribute in a response, either in its session creation response, or (if it has not received the identity from the &server; by that time) in any subsequent response to the client. If it established a secure connection to the &server; (as defined in Initiating an HTTP Session), then in the same response the connection manager SHOULD also include the 'secure' attribute set to "true" or "1".
After the client has successfully completed all required preconditions, it can send and receive XML stanzas via the HTTP binding.