XEP-0115

来自Jabber/XMPP中文翻译计划
跳转到: 导航, 搜索


本文的英文原文来自XEP-0115

XEP-0115: 实体能力

摘要: 本文定义了一个XMPP协议扩展, 用于广播和动态查询客户端,设备,或通用实体的能力. 为了最小化网络冲击, 传输机制采用标准的XMPP出席信息广播(从而防止和服务发现数据相关的数据轮询的需要), 能力信息可被缓存在单个会话中也可以贯穿多个会话,并且格式已经尽可能保持最小.

作者: Joe Hildebrand, Peter Saint-Andre, Remko Tronçon, Jacek Konieczny

版权: © 1999 - 2010 XMPP标准化基金会(XSF). 参见法律通告.

状态: 草案

类型: 标准跟踪

版本: 1.5

最后更新日期: 2008-02-26

注意: 这里定义的协议是XMPP标准化基金会的一个草案标准.对本协议的执行是被鼓励的,也适于布署到生产系统,但是在它成为最终标准之前可能还会有一些变动.

目录

绪论

动机

对于一个XMPP应用程序,经常需要(通常但不一定是一个客户端)根据从另一个应用收到的出席信息所了解到的能力采取不同的动作。例如:

  • 根据其他实体的能力显示不同系列的图标。
  • 不发送XHTML-IM[1]或者其他富文本给只支持纯文本的客户端比如手机。
  • 只有当客户端支持Jingle[2] 和Jingle RTP Sessions [3]时,才允许VoIP的初始化
  • 如果另一个用户客户端不支持SI File Transfer,那么不显示“发送文件”按钮。
  • 基于声明的订阅者兴趣,过滤Publish-Subscribe [5] 通知。

过去,对于一些Jabber客户端,在登录了之后会发送服务发现\[6\]和软件版本\[7\]请求给每个收到出席信息的实体。disco/version流信息会过度的使用带宽在大规模情况下,不实用,特别是对于有很多联系人的用户。因此本文档定义了一个健壮的、可实现的解决方案:即,基于出席信息机制\[8\]交换实体能力信息。客户端不应该遵循旧的“disco/version流”行为,而应该使用在此处定义的实体能力。

如何工作

这一节提供了关于实体能力(“caps”)的友好介绍。

想象你就是莎士比亚作品中的朱丽叶,你的一个联系人,一个帅小伙罗密欧,现在上线了。他的客户端想要发布他的能力,通过在出席信息中加入含有指定属性的<c/>元素来发布能力。结果,你的客户端受到如下出席信息:

<presence from='romeo@montague.lit/orchard'>
  <c xmlns='http://jabber.org/protocol/caps' 
     hash='sha-1'
     node='http://code.google.com/p/exodus'
     ver='QgayPKawpkPSDYmwT/WM94uAlu0='/>
</presence>

“node”属性代表了罗密欧正使用的客户端软件。“ver”属性是一个指定的构造的字符串(被称为“验证”字符串),代表了实体服务发现的标识(目录和类型在<http://www.xmpp.org/registrar/disco-categories.html>注册,同样,xml:lang和name是可选的)以及支持的特性(在<http://www.xmpp.org/registrar/disco-features.html>中注册,同样,可选的,扩展服务发现信息在<http://www.xmpp.org/registrar/formtypes.html>注册)。

此时,你的客户端根据'QgayPKawpkPSDYmwT/WM94uAlu0='字符串还不知道对方的能力。因此你的客户端发送服务发现来查询罗密欧,询问他的客户端能做什么。

<iq from='juliet@capulet.lit/chamber' 
    id='disco1'
    to='romeo@montague.lit/orchard' 
    type='get'>
  <query xmlns='http://jabber.org/protocol/disco#info'
         node='http://code.google.com/p/exodus#QgayPKawpkPSDYmwT/WM94uAlu0='/>
</iq>

应答是:

<iq from='romeo@montague.lit/orchard' 
    id='disco1'
    to='juliet@capulet.lit/chamber' 
    type='result'>
  <query xmlns='http://jabber.org/protocol/disco#info'
         node='http://code.google.com/p/exodus#QgayPKawpkPSDYmwT/WM94uAlu0='>
    <identity category='client' name='Exodus 0.9.1' type='pc'/>
    <feature var='http://jabber.org/protocol/caps'/>
    <feature var='http://jabber.org/protocol/disco#info'/>
    <feature var='http://jabber.org/protocol/disco#items'/>
    <feature var='http://jabber.org/protocol/muc'/>
  </query>
</iq>

此时,你的客户端知道声明版本字符串'QgayPKawpkPSDYmwT/WM94uAlu0='的联系人支持Multi-User Chat\[9\]以及其他罗密欧返回的特性,因为联系人事实上使用了和罗密欧同一个客户端的相同版本,相同的特性,插件,以及现在的客户端名称,就像(比如,相同的验证字符串的生成方法的输入)。你的客户端记录这些信息,所以不需要再显式地使用相同版本的字符串来查询联系人能力。例如:你的护士可以使用和罗密欧相同的客户端:

<presence from='nurse@capulet.lit/chamber'>
  <c xmlns='http://jabber.org/protocol/caps' 
     hash='sha-1'
     node='http://code.google.com/p/exodus'
     ver='QgayPKawpkPSDYmwT/WM94uAlu0='/>
</presence>

因此你了解到她也支持和罗密欧相同的特性。

另一方面,对于一个以下出席信息的人 ...

<presence from='benvolio@capulet.lit/230193'>
  <c xmlns='http://jabber.org/protocol/caps' 
     hash='sha-1'
     node='http://psi-im.org'
     ver='q07IKJEyjvHSyhy//CH0CxmKi8w='/>
</presence>

... 或者如下出席信息 ...

<presence from='bard@shakespeare.lit/globe'>
  <c xmlns='http://jabber.org/protocol/caps' 
     hash='sha-1'
     node='http://www.chatopus.com'
     ver='zHyEOgxTrkpSdGcQKH8EFPLsriY='/>
</presence>

... 你不知道联系人的客户端的能力除非你缓存了先前的实体能力信息;因此你需要再次通过服务发现查询能力。

假设

本文档做了几个假设:

  • 花名册的联系人对于我正使用的客户端标识感兴趣。
  • 我花名册上的联系人的客户端可能需要基于我的能力来构建用户界面。
  • 社区的成员趋向集中使用少部分的客户端并使用少部分的实体能力。更特殊的,在花名册里多人使用相同客户端,他们相对地升级版本较慢(通常一年好几次,可能大部分一星期一次,肯定不是每分钟一次)。
  • 一些客户端在不需要服务器与服务器连接的网络上运行,并且不需要通过HTTP访问Internet。
  • 2个互相都不在对方花名册里的人互相聊天是有可能的。
  • 客户端能力可能在交换出席信息的过程中改变,比如特性被允许或禁止。

要求

此处定义的协议满足以下要求:

  1. 客户端必须支持即使他们只支持XMPP Core \[11\], XMPP IM \[12\]和XEP-0030
  2. 客户端必须参与,即使他们所在的网络无法连接其他XMPP服务器,提供特定XMPP扩展的服务,或者HTTP服务器\[13\]。
  3. 客户端必有能力接收信息,即使没有查询他们通讯的每一个实体。
  4. 由于出席信息通常会广播给很多联系人,建议的扩展信息的字节数必须尽可能小。
  5. 必须能够编写一个XEP-0045服务实现用来单独传递给定的信息。
  6. 必须能够使用一个单独的出席信息会话来发布能力的变化。
  7. 为了完成以上工作而超过XMPP Core和XMPP IM定义的服务器基础架构不是必需的,尽管附加的服务器架构可以被用来出于优化目标。
  8. 在此定义的机制不仅限于客户端,但是对于服务器,组件或其他网络实体也必须是有用的。

协议

实体能力封装在<c/>元素中并且被'http://jabber.org/protocol/caps'限定。<c/>元素的属性如下。

表格 1: 属性

名称 定义 是否包含
ext nametaokens集合制定了附加的特性;该属性是不鼓励的(参考本文档的“合法的格式”部分) 不鼓励的
hash 该哈希算法被用来生成验证字符串;参考关于哈希算法的“强制实现的技术”部分。 必需的
node 标识了软件的唯一的URI,典型的,URL可以是生产该软件的项目主页或者公司主页。* 必需的
ver 一个字符串,用于核查身份以及实体支持的特性. ** 必需的
  • 注意:'node'属性的值是推荐的,可以是找到软件产品的更多信息的HTTP URL,比如Psi客户端的URL"http://psi-im.org";这允许应用程序为了该程序生成一个唯一字符串,它能够维护一个已知的实现的软件的列表(比如,通过disco#info接收到的URL的名称
    • 注意:在这份说明的1.4版本之前,'ver'属性用来指出软件的发布版本;'ver'属性的值取决于在这里使用的向后兼容的算法,应用程序应该(SHOULD)适当的处理遗留格式。

认证字符串

生成方法

为了帮助防止实体信息的损坏,认证字符串的值必须(MUST)根据以下方法生成。

注意:所有排序操作必须(MUST)使用在9.3部分的RFC 4790\[14\]指定的"i;octet"集合来排序。

1. 初始化一个空的字符串 S 。

2. 先根据目录再根据类型来排序服务发现标识,然后再根据xml:lang(如果存在),根据CATEGORY '/' [TYPE] '/' [LANG] '/' [NAME]格式化。注意每条斜杠都必须包含,即使TYPE, LANG,或者NAM没有被包含。

3. 对于每个标识,在'<'字符后添加'category/type/lang/name'到字符串S。

4. 排序支持的服务发现特性\[17\]。

5. 对于每个特性,在'<'字符后添加特性到字符串S。

6. 如果服务发现信息响应中包含XEP-0128数据表单,那么根据FORM_TYPE排序表单(换言之,根据<value/>元素的字符数据)。

7. 对于每个扩展的服务发现信息表单:

  1. 在'<'字符后面,添加FORM_TYPE字段<value/>元素的XML字符。
  2. 根据"var"属性的值排序字段
  3. 对于每个字段:
  • 在'<'字符之后添加"var"属性的值。
  • 根据<value/>元素的xml字符排序。
  • 对于每个<value/>元素,在'<'字符后,添加XML字符。

8. 确保S是使用UTF-8编码的(RFC 3269\[18\])。

9. 使用'hash'属性指定的算法计算S的认证字符串(比如,RFC 3174\[19\]定义的SHA-1)。哈希值必须(MUST)根据二进制输出和RFC 4648\[20\]第四部分指定的Base64编码生成(注意:Base64输出不许(MUST NOT)包含空白字符和必须(MUST)设置填充字符为0)。\[21\]

简单的生成示例

考虑一个实体,它的目录是"client",服务发现类型是"pc",服务发现名称是"Exodus 0.9.1",支持的特性是"http://jabber.org/protocol/disco#info","http://jabber.org/protocol/disco#items", 和"http://jabber.org/protocol/muc"。使用SHA-1算法,认证字符串就会按如下步骤生成(注意:在认证字符串的换行符是用来提高可读性):

  1. S =
  2. 只有一个标识:"client/pc"
  3. S = 'client/pc//Exodus 0.9.1<'
  4. 排序特性:"http://jabber.org/protocol/caps", "http://jabber.org/protocol/disco#info", "http://jabber.org/protocol/disco#items", "http://jabber.org/protocol/muc"。
  5. S = 'client/pc//Exodus 0.9.1<http://jabber.org/protocol/caps<http://jabber.org/protocol/disco#info<