git-svn-id: file:///home/ksmith/gitmigration/svn/xmpp/trunk@1035 4b5297f7-1745-476d-ba37-a9c6900126ab
This commit is contained in:
Peter Saint-Andre 2007-07-11 02:55:02 +00:00
parent b224590a17
commit 9fc8be7936
1 changed files with 110 additions and 163 deletions

View File

@ -27,6 +27,12 @@
&hildjj;
&stpeter;
&remko;
<revision>
<version>1.4pre1</version>
<date>in progress, last updated 2007-07-10</date>
<initials>psa/jjh</initials>
<remark><p>In response to persistent security concerns over caps poisoning, defined method for hashing concatenation of identity and supported features.</p></remark>
</revision>
<revision>
<version>1.3</version>
<date>2007-04-10</date>
@ -102,7 +108,7 @@
<ul>
<li>Showing a different set of icons depending on the capabilities of other clients.</li>
<li>Not sending &xep0071; content to plaintext clients such as cell phones.</li>
<li>Allowing the initiation of Voice over IP (VoIP) sessions only to clients that support VoIP.</li>
<li>Allowing the initiation of a Voice over IP (VoIP) session only to clients that support &xep0166; and &xep0167;.</li>
<li>Not showing a "Send a File" button if another user's client does not support &xep0096;.</li>
</ul>
<p>Some older Jabber clients send one &xep0030; and one &xep0092; request to each entity from which they received presence after login. That "disco+version flood" results in an excessive use of bandwidth and is impractical on a larger scale, particularly for users or applications with large rosters. Therefore this document proposes a more robust and scalable solution: namely, a presence-based mechanism <note>This proposal is not limited to clients, and can be used by any entity that exchanges presence with another entity, e.g., a gateway. However, this document uses the example of clients throughout.</note> for exchanging information about entity capabilities. Clients SHOULD NOT engage in the older "disco+version flood" behavior and instead SHOULD use Entity Capabilities as specified herein.</p>
@ -111,24 +117,25 @@
<p>This section provides a friendly, non-normative introduction to the workings of entity capabilities.</p>
<p>Imagine that you are a Shakespearean character named Juliet and one of your contacts, a handsome fellow named Romeo, becomes available. His client wants to publish its capabilities, and does this by adding a &lt;c/&gt; element to its presence packets. As a result, your client receives the following presence packet:</p>
<code><![CDATA[
<presence from='romeo@montague.net/home'>
<presence from='romeo@montague.lit/home'>
<c xmlns='http://jabber.org/protocol/caps'
node='http://exodus.jabberstudio.org/caps'
ver='0.9'/>
ver='OTgwZDEyNjhjNThjNGE4ODhhOTUwZGM4MGU0NTFlZTc0MDViNDI1Mw=='/>
</presence>
]]></code>
<p>The 'node' attribute represents the client Romeo is using, and the 'ver' attribute represents the specific version of this client. At this point, your client has no idea what the capabilities are of someone with a client string 'http://exodus.jabberstudio.org/caps' and a version string '0.9'. Your client therefore sends a query to Romeo, asking what his client version can do (using service discovery):</p>
<p>The 'node' attribute represents the client Romeo is using. The 'ver' attribute is a specially-constructed string that represents the identity (see &DISCOCATEGORIES;) and supported features (see &DISCOFEATURES;) of the entity.</p>
<p>At this point, your client has no idea what the capabilities are of someone with a client string 'http://exodus.jabberstudio.org/caps' and a version string 'OTgwZDEyNjhjNThjNGE4ODhhOTUwZGM4MGU0NTFlZTc0MDViNDI1Mw=='. Your client therefore sends a service discovery query to Romeo, asking what his client can do (note that the disco#info query is sent to a node of "node#ver"):</p>
<code><![CDATA[
<iq type='get' to='romeo@montague.net/home' id='1'>
<iq type='get' from='juliet@capulet.lit/chamber' to='romeo@montague.lit/home' id='disco1'>
<query xmlns='http://jabber.org/protocol/disco#info'
node='http://exodus.jabberstudio.org/caps#0.9'/>
node='http://exodus.jabberstudio.org/caps#OTgwZDEyNjhjNThjNGE4ODhhOTUwZGM4MGU0NTFlZTc0MDViNDI1Mw=='/>
</iq>
]]></code>
<p>The response is:</p>
<code><![CDATA[
<iq type='result' from='romeo@montague.net/home' id='1'>
<iq type='result' from='romeo@montague.lit/home' to='juliet@capulet.lit/chamber' id='disco1'>
<query xmlns='http://jabber.org/protocol/disco#info'
node='http://exodus.jabberstudio.org/caps#0.9'>
node='http://exodus.jabberstudio.org/caps#OTgwZDEyNjhjNThjNGE4ODhhOTUwZGM4MGU0NTFlZTc0MDViNDI1Mw=='>
<identity category='client' type='pc'/>
<feature var='http://jabber.org/protocol/disco#info'/>
<feature var='http://jabber.org/protocol/disco#items'/>
@ -137,97 +144,43 @@
</query>
</iq>
]]></code>
<p>At this point, your client knows that anyone using the client string 'http://exodus.jabberstudio.org/caps' and the version string '0.9' has a client that can do MUC. Your client remembers this information, such that it does not need to explicitly query the capabilities of a contact with the exact same client and version string. For example, Benvolio may send you the following presence:</p>
<p>At this point, your client knows that anyone advertising a version string of 'OTgwZDEyNjhjNThjNGE4ODhhOTUwZGM4MGU0NTFlZTc0MDViNDI1Mw==' has a client that can do MUC. Your client remembers this information, so that it does not need to explicitly query the capabilities of a contact with the same version string. For example, Benvolio may send you the following presence:</p>
<code><![CDATA[
<presence from='benvolio@capulet.com/230193'>
<presence from='benvolio@capulet.lit/230193'>
<c xmlns='http://jabber.org/protocol/caps'
node='http://exodus.jabberstudio.org/caps'
ver='0.9'/>
ver='OTgwZDEyNjhjNThjNGE4ODhhOTUwZGM4MGU0NTFlZTc0MDViNDI1Mw=='/>
</presence>
]]></code>
<p>Now your client automatically knows that Benvolio can do MUC, without needing to ask him explicitly via service discovery.</p>
<p>On the other hand, for a person with the following presence ...</p>
<code><![CDATA[
<presence from='bob@initech.com/Home'>
<presence from='nurse@capulet.lit/chamber'>
<c xmlns='http://jabber.org/protocol/caps'
node='http://exodus.jabberstudio.org/caps'
ver='0.10'/>
ver='NWExN2ZhNGI0Zjk1OWM5NDY0MTM4OGQyZjA5ZTNkMDk3YTUzZGY1OA=='/>
</presence>
]]></code>
<p>... or the following presence ...</p>
<code><![CDATA[
<presence from='bard@shakespeare.lit/globe'>
<c xmlns='http://jabber.org/protocol/caps'
node='http://psi-im.org/caps'
ver='0.9'/>
node='http://www.chatopus.com/caps'
ver='YjlhNjEwNjJkMTk3ZTdjM2YyNmQ5MjliY2ZkN2I5NDQwMDJhYTAyOA=='/>
</presence>
]]></code>
<p>... you have no information about what this contact's client is capable of (as he is using a different client/version), and you therefore need to query his capabilities explicitly again.</p>
<p>So that is how the 'node' and 'ver' attributes work. But most clients also allow certain features to be turned on or off at run time. For example, clients can allow users to turn off the exchange of chat states (for privacy reasons). For such a client, this means that it cannot just advertise its capabilities as was done before, since this capabilitiy depends on whether or not the user has turned the option on or off (and capabilities for the same client/version are assumed to be identical for all contacts). Such capabilities are advertised using "extensions". For example:</p>
<code><![CDATA[
<presence from='benvolio@capulet.com/230193'>
<c xmlns='http://jabber.org/protocol/caps'
node='http://exodus.jabberstudio.org/caps'
ver='0.9'
ext='csn'/>
</presence>
]]></code>
<p>In this case, Benvolio is using an extension that his client calls 'csn'. Again, your client has no clue what 'csn' means, as it is a name arbitrarily chosen by Benvolio's client. It therefore queries Benvolio's client to find out what a client 'http://exodus.jabberstudio.org/caps' means when it says it supports 'csn'. It does this by sending a disco#info request to the node#ext (not the node#ver as was done to find the base capabilities):</p>
<code><![CDATA[
<iq type='get' to='romeo@montague.net/home' id='2'>
<query xmlns='http://jabber.org/protocol/disco#info'
node='http://exodus.jabberstudio.org/caps#csn'/>
</iq>
]]></code>
<p>The response is:</p>
<code><![CDATA[
<iq type='result' from='romeo@montague.net/home' id='2'>
<query xmlns='http://jabber.org/protocol/disco#info'
node='http://exodus.jabberstudio.org/caps#0.9'>
<feature var='http://jabber.org/protocol/chatstates'/>
</query>
</iq>
]]></code>
<p>Now, your client knows that Benvolio's client (and anyone using the same client node as Benvolio and extension 'csn', since the 'ext' values MUST be stable across client versions) supports chat state notifications. <em>The sum total of what Benvolio's client supports is the set of features advertised in disco#info responses to the node#ver (base features) and the set of features advertised in disco#info responses to each node#ext (extension features).</em></p>
<p>However, suppose Bill logs on:</p>
<code><![CDATA[
<presence from='bard@shakespeare.lit/globe'>
<c xmlns='http://jabber.org/protocol/caps'
node='http://psi-im.org/caps'
ver='0.9'
ext='csn'/>
</presence>
]]></code>
<p>Although you know that 'csn' meant "chat state notifications" for Benvolio (and for everyone using the same client as Benvolio), you do not know what this means for Bill, because he is using a different client! So you need to query his client:</p>
<code><![CDATA[
<iq type='get' to='bard@shakespeare.lit/globe' id='3'>
<query xmlns='http://jabber.org/protocol/disco#info'
node='http://psi-im.org/caps#csn'/>
</iq>
]]></code>
<p>and the response ...</p>
<code><![CDATA[
<iq type='result' from='bard@shakespeare.lit/globe' id='3'>
<query xmlns='http://jabber.org/protocol/disco#info'
node='http://psi-im.org/caps#0.9'>
<feature var='urn:xmpp:ssn'/>
</query>
</iq>
]]></code>
<p>... reveals that this client uses 'csn' to denote the capability of "stanza session negotiation" (formerly known as "chat session negotiation"). So although the 'ext' values are stable for each client (and for all versions thereof), they are not stable across different clients.</p>
<p>... you have no information about what this contact's client is capable of (as he is using a different client/version), and you therefore need to query for capabilities explicitly again via service discovery.</p>
</section2>
</section1>
<section1 topic='Assumptions' anchor='assumptions'>
<p>This document makes several assumptions:</p>
<ul>
<li>The type of client I am using is of interest to the people on my roster.</li>
<li>The type of client I am using is of interest to the people in my roster.</li>
<li>Clients for the people on my roster might want to make user interface decisions based on my capabilities.</li>
<li>Different instances of the same client (including version) have the same base capabilities.</li>
<li>Some clients will have bundles of functionality that can be enabled and disabled.</li>
<li>One instance of a given client may not know about all of the possible bundles of functionality that can be enabled and disabled (for example, plugins written to a client SDK).</li>
<li>Members of a community tend to cluster around a small set of clients. More specifically, multiple people in my roster use the same client, and they upgrade versions relatively slowly (commonly a few times a year, perhaps once a week at most, certainly not once a minute).</li>
<li>Different clients may support the same capabilities.</li>
<li>Members of a community tend to cluster around a small set of clients. More specifically, multiple people in my roster use the same client, and they upgrade versions relatively slowly (commonly a few times a year, perhaps once a week at most, certainly not once a minute).</li>
<li>Some clients are running against servers without server-to-server connectivity enabled, and without access to the Internet via HTTP.</li>
<li>Conversations are possible between users who are not on each other's roster.</li>
<li>Conversations are possible between users who are not on each other's rosters.</li>
<li>Client capabilities may change over the course of a session, due to features being enabled and disabled.</li>
</ul>
</section1>
@ -245,49 +198,94 @@
</ol>
</section1>
<section1 topic='Protocol' anchor='protocol'>
<p>Entity capabilities are encapsulated in a &lt;c/&gt; element qualified by the 'http://jabber.org/protocol/caps' namespace. The attributes of the &lt;c/&gt; element are as follows:</p>
<table caption='Attributes'>
<tr>
<th>Name</th>
<th>Definition</th>
<th>Inclusion</th>
</tr>
<tr>
<td>ext</td>
<td>A set of nametokens specifying additional feature bundles; this attribute is deprecated.</td>
<td>OPTIONAL</td>
</tr>
<tr>
<td>hash</td>
<td>The hashing algorithm used in generated the 'ver' attribute (see &ianahashes;); the value defaults to "sha-1".</td>
<td>OPTIONAL</td>
</tr>
<tr>
<td>node</td>
<td>A unique identifier for the software underlying the entity, typically a URL at the website of the project or company that produces the software.</td>
<td>REQUIRED</td>
</tr>
<tr>
<td>ver</td>
<td>A string that specifies the identity and supported features of the entity. <note>Before version 1.4 of this specification, the 'ver' attribute was used to specify the released version of the software.</note></td>
<td>REQUIRED</td>
</tr>
</table>
</section1>
<section1 topic='Generation of ver Attribute' anchor='ver'>
<p>In order to help prevent poisoning of entity capabilities information, the value of the 'ver' attribute MUST be generated according to the following method.</p>
<p>Note: All sorting operations MUST be performed using "i;octet" collation as specified in Section 9.3 of &rfc4790;.</p>
<ol>
<li>Initialize an empty string S.</li>
<li>Sort the service discovery identities by category and then by type.</li>
<li>For each identity, append the category and then the type (if it exists) to S.</li>
<li>Sort the supported features.</li>
<li>For each feature, append the feature to S.</li>
<li>Compute H by hashing S using the SHA-1 algorithm as specified in &rfc3174; (where the output is hexadecimal-encoded, not binary).</li>
<li>Compute ver by encoding H using Base64 as specified in Section 4 of &rfc4648;.</li>
</ol>
<p>For example, consider an entity whose service discovery category is "client", whose service discovery type is "pc", and whose supported features are "http://jabber.org/protocol/disco#info", "http://jabber.org/protocol/disco#items", "http://jabber.org/protocol/feature-neg", and "http://jabber.org/protocol/muc". The value of the 'ver' attribute would be generated as follows:</p>
<ol>
<li>E = ''</li>
<li>Only one identity: client/pc</li>
<li>E = clientpc</li>
<li>Sort the features: "http://jabber.org/protocol/disco#info", "http://jabber.org/protocol/disco#items", "http://jabber.org/protocol/feature-neg", "http://jabber.org/protocol/muc".</li>
<li>E = clientpchttp://jabber.org/protocol/disco#infohttp://jabber.org/protocol/disco#itemshttp://jabber.org/protocol/feature-neghttp://jabber.org/protocol/muc</li>
<li>H = 980d1268c58c4a888a950dc80e451ee7405b4253</li>
<li>ver = OTgwZDEyNjhjNThjNGE4ODhhOTUwZGM4MGU0NTFlZTc0MDViNDI1Mw==</li>
</ol>
</section1>
<section1 topic='Use Cases' anchor='usecases'>
<section2 topic='Advertising Capabilities' anchor='advertise'>
<p>Each time a conformant client sends presence, it annotates that presence with an element that specifies the client type, the version of that client, and which feature bundles (if any) are currently enabled. Unless the server optimizations shown later are being used, the client MUST send this with every presence change (except for unavailable presence) to enable existing servers to remember the last presence for use in responding to probes. The client MUST send the <strong>'node'</strong> and <strong>'ver'</strong> attributes.</p>
<p>In addition, the client MAY send an <strong>'ext'</strong> attribute (short for "extensions") if it has one or more feature bundles to advertise. A feature bundle is any non-standard addition or extension to the core application, such as a client plugin. If more than one feature bundle is advertised, the value of the <strong>'ext'</strong> attribute MUST be a space-separated list of bundle names.
<note>Each extension name MUST be of type NMTOKEN, where multiple extension names are separated by the white space character #x20, resulting in a tokenized attribute type of NMTOKENS (see Section 3.3.1 of &w3xml;).</note>
The client MUST NOT send an <strong>'ext'</strong> attribute if there are no interesting non-core features enabled. The names of the feature bundles MUST NOT be used for semantic purposes: they are merely opaque identifiers that will be used in other use cases. However, a client MUST ensure that the same 'ext' value refers to the same feature bundle across client versions (i.e., different values of the 'ver' attribute). If bundles are added or substracted during an entity's session (e.g., a user plugs in a video camera), the entity SHOULD update the value of the 'ext' attribute to reflect the changed capabilities and send a new presence broadcast. If a feature bundle itself changes in any way (e.g., a user installs an updated version of a client plugin), the application MUST change the bundle name and SHOULD send a new presence broadcast.</p>
<p>Note: The values of the <strong>'node'</strong>, <strong>'ver'</strong>, and <strong>'ext'</strong> attributes MUST NOT contain the '#' character, since that character is used as a separator in the <link url="#discover">Discovering Capabilities</link> use case.</p>
<p>Each time a conformant client sends presence, it annotates that presence with a client identifier ('node' attribute) and identity and feature identifier ('ver' attribute). Unless the server optimizations shown later are being used, the client MUST send this with every presence change (except for unavailable presence) to enable existing servers to remember the last presence for use in responding to probes.</p>
<p>If the supported features change during a client's session (e.g., a user installs an updated version of a client plugin), the application MUST recompute the 'ver' attribute and SHOULD send a new presence broadcast.</p>
<p>Note: The values of the <strong>'node'</strong> and <strong>'ver'</strong> attributes MUST NOT contain the '#' character, since that character is used as a separator in the <link url="#discover">Discovering Capabilities</link> use case.</p>
<example caption='Annotated presence sent'><![CDATA[
<presence>
<c xmlns='http://jabber.org/protocol/caps'
node='http://exodus.jabberstudio.org/caps'
ver='0.9'/>
</presence>
]]></example>
<example caption='Annotated presence sent, with feature extensions'><![CDATA[
<presence>
<c xmlns='http://jabber.org/protocol/caps'
node='http://exodus.jabberstudio.org/caps'
ver='0.9'
ext='93j 1g'/>
ver='OTgwZDEyNjhjNThjNGE4ODhhOTUwZGM4MGU0NTFlZTc0MDViNDI1Mw=='/>
</presence>
]]></example>
</section2>
<section2 topic="Discovering Capabilities" anchor='discover'>
<p>Once someone on my roster knows what client I am using, they need to be able to figure out what features are supported by that client. In the deprecated "disco flood" approach, this has been done by sending one "disco#info" request to each entity in a user's roster. Entity capabilities makes that unnecessary through the use of annotated presence. In particular, a client that receives the annotated presence sends a <strong>disco#info</strong> request (as defined in <strong>XEP-0030: Service Discovery</strong>) to <em>exactly</em> one of the users that sent a particular combination of <strong>node</strong> and <strong>ver</strong>. If the requestor has received the same annotation from multiple JIDs, the requestor SHOULD pick a random JID from that list to which the requestor will send the <strong>disco#info</strong> request.</p>
<p>A contact can learn what features a user's client supports by sending a disco#info request (as defined in <strong>XEP-0030: Service Discovery</strong>) to any client that sent a particular value of the <strong>ver</strong> attribute. If the requestor has received the same annotation from multiple JIDs, the requestor SHOULD pick a random JID from that list to which the requestor will send the <strong>disco#info</strong> request.</p>
<p>The <strong>disco#info</strong> request is sent to a JID + node combination that consists of the chosen <strong>&lt;user@host/resource&gt;</strong> JID and a service discovery <strong>node</strong> that is constructed as follows: concatenate (1) the value of the caps <strong>'node'</strong> attribute, (2) the "#" character, and (3) the version number specified in the caps <strong>'ver'</strong> attribute.</p>
<example caption='Disco#info request for client#version'><![CDATA[
<iq type='get' from='bard@shakespeare.lit/globe' to='randomuser1@capulet.com/resource' id='123'>
<iq type='get' from='bard@shakespeare.lit/globe' to='randomuser1@capulet.lit/resource' id='123'>
<query xmlns='http://jabber.org/protocol/disco#info'
node='http://exodus.jabberstudio.org/caps#0.9'/>
node='http://exodus.jabberstudio.org/caps#OTgwZDEyNjhjNThjNGE4ODhhOTUwZGM4MGU0NTFlZTc0MDViNDI1Mw=='/>
</iq>
]]></example>
<p>The random user then returns all of the capabilities supported by the base installation of the application without plugins or other add-ons:</p>
<example caption='Disco#info response for client#version'><![CDATA[
<iq type='result' from='randomuser1@capulet.com/resource' to='bard@shakespeare.lit/globe' id='123'>
<iq type='result' from='randomuser1@capulet.lit/resource' to='bard@shakespeare.lit/globe' id='123'>
<query xmlns='http://jabber.org/protocol/disco#info'
node='http://exodus.jabberstudio.org/caps#0.9'>
node='http://exodus.jabberstudio.org/caps#OTgwZDEyNjhjNThjNGE4ODhhOTUwZGM4MGU0NTFlZTc0MDViNDI1Mw=='>
<identity category='client' type='pc'/>
<feature var='http://jabber.org/protocol/disco#info'/>
<feature var='http://jabber.org/protocol/disco#items'/>
@ -296,64 +294,6 @@
</query>
</iq>
]]></example>
<p>Subsequent requests MAY be made to determine the supported features associated with each extension. These requests MUST be sent to a random <strong>&lt;user@host/resource&gt;</strong> JID that sent a caps annotation that included a particular <strong>node</strong>/<strong>ext</strong> combination. The <strong>disco#info</strong> request shall be sent to a JID + node combination that consists of the chosen JID and a service discovery <strong>node</strong> that is constructed as follows: concatenate (1) the value of the caps <strong>'node'</strong> attribute, (2) the "#" character, and (3) the extension name specified by one of the space-separated names in the caps <strong>'ext'</strong> attribute. The requestor SHOULD try to use different JIDs for each of these requests, as well as for the first request.</p>
<example caption='Disco#info request for client#extension'><![CDATA[
<iq type='get' from='bard@shakespeare.lit/globe' to='randomuser3@capulet.com/resource' id='234'>
<query xmlns='http://jabber.org/protocol/disco#info'
node='http://exodus.jabberstudio.org/caps#93j'/>
</iq>
]]></example>
<example caption='Disco#info response for client#extension'><![CDATA[
<iq type='result' from='randomuser3@capulet.com/resource' to='bard@shakespeare.lit/globe' id='234'>
<query xmlns='http://jabber.org/protocol/disco#info'
node='http://exodus.jabberstudio.org/caps#93j'>
<identity category='client' type='pc'/>
<feature var='http://jabber.org/protocol/bytestreams'/>
<feature var='http://jabber.org/protocol/si'/>
<feature var='http://jabber.org/protocol/si/profile/file-transfer'/>
</query>
</iq>
]]></example>
<example caption='Disco#info request for client#extension'><![CDATA[
<iq type='get' from='bard@shakespeare.lit/globe' to='randomuser4@capulet.com/resource' id='345'>
<query xmlns='http://jabber.org/protocol/disco#info'
node='http://exodus.jabberstudio.org/caps#1g'/>
</iq>
]]></example>
<example caption='Disco#info response for client#extension'><![CDATA[
<iq type='result' from='randomuser4@capulet.com/resource' to='bard@shakespeare.lit/globe' id='345'>
<query xmlns='http://jabber.org/protocol/disco#info'
node='http://exodus.jabberstudio.org/caps#1g'>
<identity category='client' type='pc'/>
<feature var='http://jabber.org/protocol/xhtml-im'/>
</query>
</iq>
]]></example>
<p>Note: The set of features that a given entity advertises in response to a "client#version" request and all "client#extension" requests MUST be equivalent to the response it gives to a <strong>disco#info</strong> request with no 'node' attribute:</p>
<example caption='Generic disco#info response'><![CDATA[
<iq type='result' from='randomuser2@capulet.com/resource' to='bard@shakespeare.lit/globe' id='456'>
<query xmlns='http://jabber.org/protocol/disco#info'>
<identity category='client' type='pc'/>
<feature var='http://jabber.org/protocol/disco#info'/>
<feature var='http://jabber.org/protocol/disco#items'/>
<feature var='http://jabber.org/protocol/feature-neg'/>
<feature var='http://jabber.org/protocol/muc'/>
<feature var='http://jabber.org/protocol/bytestreams'/>
<feature var='http://jabber.org/protocol/si'/>
<feature var='http://jabber.org/protocol/si/profile/file-transfer'/>
<feature var='http://jabber.org/protocol/xhtml-im'/>
</query>
</iq>
]]></example>
<p>All of the responses to the <strong>disco#info</strong> queries SHOULD be cached. If a particular entity cannot store the responses, it SHOULD NOT make the requests. An entity SHOULD NOT make the service discovery requests unless the information is required for some local functionality. An entity MUST NOT ever make a request to another entity that has the same version of the same application as the requesting entity, except for extensions that are not supported by the requestor's installation (e.g., one "Exodus 0.9" client MUST NOT query another "Exodus 0.9" client unless the second client has advertised an extension or plugin that the first client does not have).</p>
</section2>
<section2 topic='Stream Feature' anchor='stream'>
@ -362,7 +302,7 @@
<stream:features>
<c xmlns='http://jabber.org/protocol/caps'
node='http://jabberd.org/entity'
ver='1.6.1'/>
ver='YThjZWU2MTE0MDVkMmE5N2U0MjYzZWU1ZDI2MzNmOWUyNGRhNmQwNA=='/>
</stream:features>
]]></example>
</section2>
@ -371,17 +311,17 @@
<section1 topic='Server Optimizations' anchor='optimizations'>
<p>A server that is managing an entity's session MAY choose to optimize traffic through the server. In this case, the server MAY strip off redundant capabilities annotations. Because of this, receivers of annotations MUST NOT expect an annotation on every presence packet they receive. If the server wants to perform this traffic optimization, it MUST ensure that the first presence each subscriber receives contains the annotation. The server MUST also ensure that any changes in the annotation (typically in the <strong>'ext'</strong> attribute) are sent to all subscribers.</p>
<p>A client MAY query the server using <strong>disco#info</strong> to determine if the server supports the <strong>'http://jabber.org/protocol/caps'</strong> feature. If so, the server MUST perform the optimization delineated above, and the client MAY choose to only send the capabilities annotation on the first presence packet, as well as whenever its capabilities change.</p>
<p>A client MAY query the server using <strong>disco#info</strong> to determine if the server supports the <strong>'http://jabber.org/protocol/caps'</strong> feature. If so, the server MUST perform the optimization delineated above, and the client MAY choose to send the capabilities annotation only on the first presence packet, as well as whenever its capabilities change.</p>
<example caption='Disco#info request for server optimization'><![CDATA[
<iq from='juliet@capulet.com/balcony'
to='capulet.com'
<iq from='juliet@capulet.lit/balcony'
to='capulet.lit'
type='get'>
<query xmlns='http://jabber.org/protocol/disco#info'/>
</iq>
<iq from='capulet.com'
to='juliet@capulet.com/balcony'
<iq from='capulet.lit'
to='juliet@capulet.lit/balcony'
type='result'>
<query xmlns='http://jabber.org/protocol/disco#info'>
...
@ -393,8 +333,7 @@
</section1>
<section1 topic='Implementation Notes' anchor='impl'>
<p>If two entities exchanges messages but they do not normally exchange presence (i.e., via presence subscription), the entities MAY choose to send directed presence to each other, where the presence information SHOULD be annotated with the same capabilities information as each entity sends in broadcasted presence.</p>
<p>If capabilities information has not been received from another entity, an application MUST assume that the other entity does not support capabilities.</p>
<p>If two entities exchanges messages but they do not normally exchange presence (i.e., via presence subscription), the entities MAY choose to send directed presence to each other, where the presence information SHOULD be annotated with the same capabilities information as each entity sends in broadcasted presence. If capabilities information has not been received from another entity, an application MUST assume that the other entity does not support capabilities.</p>
</section1>
<section1 topic='Error Codes' anchor='error'>
@ -402,8 +341,8 @@
</section1>
<section1 topic='Security Considerations' anchor='security'>
<p>Use of the protocol specified in this document might make some client-specific forms of attack slightly easier, since the attacker could more easily determine the type of client being used. However, since most clients respond to <strong>jabber:iq:version</strong> requests without performing access control checks, there is no new vulnerability. Entities that wish to restrict access to capabilities information SHOULD use the privacy lists protocol defined in <strong>XMPP IM</strong> to define appropriate communications blocking (e.g., an entity MAY choose to allow IQ requests only from "trusted" entities, such as those with whom it has a subscription of "both").</p>
<p>It is possible (though unlikely) for a bad actor or rogue application to poison other entities by providing incorrect information in response to disco#info requests. To guard against such poisoning, a requesting entity MAY send disco#info requests to multiple entities that match the same <strong>node</strong>/<strong>ver</strong> or <strong>node</strong>/<strong>ext</strong> combination and then compare the results to ensure consistency. The requesting entity SHOULD NOT send the same request to more than five entities and MUST ensure that the entities are truly different by not sending the same request to multiple entities for which the &lt;user@host&gt; portion matches.</p>
<p>Use of the protocol specified in this document might make some client-specific forms of attack slightly easier, since the attacker could more easily determine the type of client being used. However, since most clients respond to <strong>jabber:iq:version</strong> requests without performing access control checks, there is no new vulnerability. Entities that wish to restrict access to capabilities information SHOULD use &xep0016; to define appropriate communications blocking (e.g., an entity MAY choose to allow IQ requests only from "trusted" entities, such as those with whom it has a subscription of "both").</p>
<p>Adherence to the algorithm defined in the <link url='#ver'>Generation of ver Attribute</link> sectio of this document helps to guard against poisoning of entity capabilities information by malicious or improperly implemented entities.</p>
</section1>
<section1 topic='IANA Considerations' anchor='iana'>
@ -411,9 +350,11 @@
</section1>
<section1 topic='XMPP Registrar Considerations' anchor='registrar'>
<p>The &REGISTRAR; includes 'http://jabber.org/protocol/caps' in its registries of protocol namespaces and service discovery features.</p>
<p>If it is useful or interesting, the Registrar may also provide registration of the URIs to be used in the <strong>'node'</strong> attribute, but since these URIs can be scoped according to well-defined existing rules, this is not necessary.</p>
<section2 topic='Protocol Namespaces' anchor='ns'>
<p>The &REGISTRAR; includes 'http://jabber.org/protocol/caps' in its registry of protocol namespaces (see &NAMESPACES;).</p>
</section2>
</section1>
<section1 topic='XML Schema' anchor='schema'>
<code><![CDATA[
<?xml version='1.0' encoding='UTF-8'?>
@ -436,6 +377,7 @@
<xs:simpleContent>
<xs:extension base='empty'>
<xs:attribute name='ext' type='xs:NMTOKENS' use='optional'/>
<xs:attribute name='hash' type='xs:NMTOKEN' use='optional' default='sha-1'/>
<xs:attribute name='node' type='xs:string' use='required'/>
<xs:attribute name='ver' type='xs:string' use='required'/>
</xs:extension>
@ -452,4 +394,9 @@
</xs:schema>
]]></code>
</section1>
<section1 topic='Acknowledgements' anchor='ack'>
<p>Thanks to Rachel Blackman, Dave Cridland, Richard Dobson, Sergei Golovan, Justin Karneges, Jacek Konieczny, Ian Paterson, Kevin Smith, Tomasz Sterna, and Michal Vaner for comments and suggestions.</p>
</section1>
</xep>